라벨 그 이상: ResNet-50과 Explainable AI(Grad-CAM)를 활용한 피부 병변 분류기 구축
Source: Dev.to
Introduction
의료 AI 데모를 보면서 “물론, 이것이 발진이라고 말하지만 모델이 정확히 무엇을 보고 있는 걸까?” 라고 생각해 본 적 있나요? 컴퓨터 비전과 의료 AI 분야에서 블랙 박스 문제는 단순한 기술적 장벽이 아니라 신뢰의 장벽이기도 합니다.
피부 병변 스크리닝 도구를 만들 때, 단순히 퍼센트 점수만으로는 충분하지 않습니다. 진정으로 유용한 도구를 만들기 위해서는 설명 가능한 AI (XAI) 가 필요합니다. 이 가이드에서는:
- PyTorch와 FastAI를 사용해 피부 상태를 분류하는 딥러닝 파이프라인을 구축합니다.
- Grad‑CAM을 구현해 모델의 결정에 영향을 준 특징(텍스처, 색상, 경계)을 강조하는 히트맵을 생성합니다.
딥러닝, 헬스테크에 관심이 있든, 모델을 더 투명하게 만들고 싶든, 이 워크스루는 전체 엔지니어링 구현을 다룹니다.
아키텍처
우리 시스템은 추가된 Explainability Layer가 포함된 고전적인 클라이언트‑서버 모델을 따릅니다. 추론을 위해 미세 조정된 ResNet‑50을 사용하고, 사용자 경험을 위해 React Native 프론트엔드를 사용합니다.
graph TD
A[User Takes Photo] --> B(React Native App)
B --> C{FastAPI Backend}
C --> D[ResNet‑50 Classifier]
D --> E[Inference Result]
D --> F[Grad‑CAM Hook]
F --> G[Heatmap Generation]
G --> H[Overlay Image]
H --> I[Result + Visualization]
E --> I
I --> B
필수 조건
| 요구 사항 | 세부 정보 |
|---|---|
| FastAI / PyTorch | 모델 학습 및 파인튜닝 |
| Grad‑CAM | 최종 컨볼루션 레이어에서 그래디언트 추출 |
| React Native | 크로스 플랫폼 모바일 인터페이스 |
| Dataset | 예: HAM10000 (Human‑Against‑Machine, 10 k 훈련 이미지) |
Step 1: FastAI로 ResNet‑50 미세조정
FastAI는 전이 학습을 매우 효율적으로 만들어 줍니다. 아래는 피부 병변 이미지에 대해 사전 학습된 ResNet‑50을 미세조정하는 최소 스크립트입니다.
from fastai.vision.all import *
# Load data – assumes images are organized in folders by label
path = Path('./skin_lesion_data')
dls = ImageDataLoaders.from_folder(
path,
valid_pct=0.2,
item_tfms=Resize(224)
)
# Initialize Learner with ResNet‑50
learn = vision_learner(dls, resnet50, metrics=accuracy)
# Find optimal learning rate and train
learn.fine_tune(5, base_lr=3e-3)
# Export for production
learn.export('skin_classifier.pkl')
단계 2: Grad‑CAM 구현을 통한 설명 가능성
Grad‑CAM(Gradient‑weighted Class Activation Mapping)은 최종 컨볼루션 레이어로 흐르는 그래디언트를 사용하여 위치 지도(localization map)를 생성합니다.
import torch
import numpy as np
class GradCAM:
def __init__(self, model, target_layer):
self.model = model
self.target_layer = target_layer
self.gradients = None
self.activations = None
# Register hooks
self.target_layer.register_forward_hook(self._save_activation)
self.target_layer.register_full_backward_hook(self._save_gradient)
def _save_activation(self, module, input, output):
self.activations = output
def _save_gradient(self, module, grad_input, grad_output):
self.gradients = grad_output[0]
def generate_heatmap(self, input_tensor, category_idx):
# Forward pass
output = self.model(input_tensor)
self.model.zero_grad()
# Backward pass for the specific category
loss = output[0, category_idx]
loss.backward()
# Weight the activations by the gradients
weights = torch.mean(self.gradients, dim=(2, 3), keepdim=True)
heatmap = torch.sum(weights * self.activations, dim=1).squeeze()
# ReLU and normalize
heatmap = np.maximum(heatmap.detach().cpu().numpy(), 0)
heatmap /= np.max(heatmap)
return heatmap
Note: 이 코드를 API에 통합하여 진단 결과(예: “Melanocytic nevi”)와 시각적 히트맵 이미지를 모두 반환하도록 하세요.
프로덕션으로 확장
프로토타입은 좋은 시작이지만, 의료 수준 AI를 배포하려면 다음이 필요합니다:
- 엄격한 테스트 및 검증
- 데이터 프라이버시 준수 (HIPAA, GDPR 등)
- 견고한 MLOps 파이프라인
프로덕션 준비가 된 예시, 고급 컴퓨터 비전 패턴, AI 안전에 대한 심층 탐구는 **WellAlly Tech Blog**의 기술 자료를 확인하세요.
3단계: 프론트엔드 시각화 (React Native)
모바일 측면에서는 원본 이미지를 표시하고 사용자(또는 임상의)가 히트맵 오버레이를 토글할 수 있도록 합니다.
import React, { useState } from 'react';
import { View, Image, Button, Text } from 'react-native';
const ResultScreen = ({ route }) => {
const { originalUri, heatmapUri, prediction } = route.params;
const [showHeatmap, setShowHeatmap] = useState(false);
return (
<View>
<Text>Result: {prediction}</Text>
<Image source={{ uri: showHeatmap ? heatmapUri : originalUri }} style={{ width: 300, height: 300 }} />
<Button
title={showHeatmap ? "Hide Heatmap" : "Show Heatmap"}
onPress={() => setShowHeatmap(!showHeatmap)}
/>
</View>
);
};
export default ResultScreen;
import React, { useState } from "react";
import { View, Switch, Text } from "react-native";
const HeatmapToggle = () => {
const [showHeatmap, setShowHeatmap] = useState(false);
return (
<View>
<Text>Show Grad‑CAM Heatmap (Logic)</Text>
<Switch
value={showHeatmap}
onValueChange={() => setShowHeatmap(!showHeatmap)}
/>
</View>
);
};
export default HeatmapToggle;
전체 화면 제어
- 전체 화면 모드 진입
- 전체 화면 모드 종료
결론: 격차 해소
FastAI를 빠른 개발에, Grad‑CAM을 투명성에 결합함으로써 단순 분류기를 강력한 진단 보조 도구로 변환합니다. 이 설정은 단순히 답을 제공하는 것이 아니라 이유를 제공합니다.
주요 요점
- 전이 학습(ResNet‑50)은 수 주간의 훈련 시간을 절약합니다.
- 해석 가능성은 의료와 같은 고위험 분야에서는 절대 양보할 수 없습니다.
- 하이브리드 스택(Python 백엔드 + React Native 프론트엔드)은 AI 제품 개발자 경험을 최적화합니다.
AI 해석 가능성에 대해 어떻게 생각하시나요? 히트맵을 통해 AI의 “사고 과정”을 보여준다면 AI를 더 신뢰하실까요? 아래 댓글에서 논의해 주세요!
*이 튜토리얼이 마음에 드셨다면 ❤️와 🔖 잊지 마세요! 더 고급 AI 구현 전략을 원하시면 **WellAlly Blog*를 방문해 주세요.
