석사 과정 중 딥러닝 모델을 개발하고 연구하는 것은 많이 진행하였으나, 모델을 배포하는 경험이 없어서 이번 기회에 진행해보고자 한다.
사용할 모델은 석사 과정에서 개발한 유방 MRI 내 종양을 세그멘테이션하고 종양이 존재할 확률을 예측하는 모델이다. (classification & segmentation)
해당 프로젝트는 챗지피티와 함께 진행하였다.
챗지피티와 함께라면...모든지 가능하니까...
pip install fastapi uvicorn pydicom
from fastapi import FastAPI, HTTPException, File, UploadFile
from fastapi.responses import FileResponse, JSONResponse
from pydantic import BaseModel
from PIL import Image
import torch
import os
import cv2
from .model import load_model
from .data_utils import *
app = FastAPI(title="딥러닝 모델 API")
# 모델 로드
model = load_model("/Users/kimyoungmin/my_fastapi_app/models/Breast_MTL.pth")
@app.post("/process/")
async def process_dicom(file: UploadFile = File(...)):
try:
# DICOM 파일을 서버에 저장
dicom_file_path = f"/Users/kimyoungmin/my_fastapi_app/input_data/{file.filename}"
with open(dicom_file_path, "wb") as f:
f.write(await file.read())
# DICOM 이미지 로드 및 전처리
image_array = load_dicom_image(dicom_file_path)
dcm_forOverlay = (image_array.squeeze()*255.0).astype(np.uint8)
dcm_forOverlay = np.expand_dims(dcm_forOverlay, axis=2)
dcm_forOverlay = cv2.cvtColor(dcm_forOverlay, cv2.COLOR_GRAY2BGR)
# 모델에 입력할 형태로 변환 (예: 배치 크기 추가)
input_tensor = torch.tensor(image_array, dtype=torch.float32)
# 모델 추론
with torch.no_grad():
_, _, prediction, output_img = model(input_tensor)
prediction = prediction.item()
output_img = torch.sigmoid(output_img).squeeze().cpu().numpy()
output_img = (output_img * 255.0).astype(np.uint8)
output_img = np.expand_dims(output_img, axis=2)
output_img = cv2.applyColorMap(output_img, cv2.COLORMAP_JET)
output_img[:, :, 0] = 0 # 빨간색으로 설정
output_img = output_img[:, :, ::-1]
alpha = 0.7 # 원본 이미지와 overlay 이미지의 가중치 조절
overlay_result = cv2.addWeighted(dcm_forOverlay, alpha, output_img, 1 - alpha, 0)
# 결과 PNG 파일 저장
png_file_path = f"/Users/kimyoungmin/my_fastapi_app/output_data/{os.path.splitext(file.filename)[0]}.png"
save_png(overlay_result, png_file_path)
prediction = f"{prediction:.4f}"
# 실수 값과 PNG 파일 경로 반환
return JSONResponse({
"prediction": prediction,
"png_file": png_file_path
})
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.get("/download_png/")
async def download_png(file_path: str):
if os.path.exists(file_path):
return FileResponse(file_path, media_type="image/png", filename=os.path.basename(file_path))
else:
raise HTTPException(status_code=404, detail="File not found")
uvicorn app.main:app --reload
curl -X POST "http://127.0.0.1:8000/process/" -F "file=@/Users/kimyoungmin/my_fastapi_app/input_data/1329490_7069718_20151589.dcm"
curl -X GET "http://127.0.0.1:8000/download_png/?file_path=/Users/kimyoungmin/my_fastapi_app
/output_data/1329490_7069718_20151589.png" -o /Users/kimyoungmin/Downloads/downloaded_image.png
현재까지는 API를 실행하는 것까지 진행해보았는데, 실제 배포하는 것까지 진행하여 블로그에 리뷰할 예정이다.