์ด๋ฏธ์ง ๊ธฐ๋ฐ ์ง๋ณ ์ง๋จ์ ์ํ Python AI ์๋ฒ์ ๋๋ค. Flask ์น ํ๋ ์์ํฌ์ PyTorch ๋ฅ๋ฌ๋ ๋ชจ๋ธ์ ์ฌ์ฉํ์ฌ ๊ตฌ์ถ๋์์ต๋๋ค.
- ์ด๋ฏธ์ง ์ ๋ก๋: ๋ค์ํ ์ด๋ฏธ์ง ํ์ ์ง์ (PNG, JPG, JPEG, GIF, BMP)
- AI ์ง๋จ: PyTorch ๋ชจ๋ธ์ ์ฌ์ฉํ ์๋ ์ง๋ณ ์ง๋จ
- GradCAM ์๊ฐํ:
- ์๋ณธ ์ด๋ฏธ์ง, ํํธ๋งต, ์ค๋ฒ๋ ์ด ์ด๋ฏธ์ง ์ ๊ณต
- AI ํ๋จ ๊ทผ๊ฑฐ์ ์๊ฐ์ ์ค๋ช
- Base64 ์ธ์ฝ๋ฉ์ผ๋ก ์น ์นํ์ ์ ์ก
- REST API: JSON ํํ์ ์๋ต์ ์ ๊ณตํ๋ RESTful API
- ์ค์๊ฐ ์ฒ๋ฆฌ: ์ด๋ฏธ์ง ์ ๋ก๋ ์ฆ์ ์ง๋จ ๊ฒฐ๊ณผ ์ ๊ณต
- ์ค๋ฅ ์ฒ๋ฆฌ: ํฌ๊ด์ ์ธ ์์ธ ์ฒ๋ฆฌ ๋ฐ ์ฌ์ฉ์ ์นํ์ ์ค๋ฅ ๋ฉ์์ง
skinseal-pythonAI/
โโโ app.py # ๋ฉ์ธ Flask ์ ํ๋ฆฌ์ผ์ด์
(์์ ๊ธฐ๋ฅ)
โโโ app_simple.py # ๊ฐ๋จํ Flask ์ ํ๋ฆฌ์ผ์ด์
(ํ
์คํธ์ฉ)
โโโ config.py # ์ค์ ๊ด๋ฆฌ
โโโ utils.py # ์ ํธ๋ฆฌํฐ ํจ์๋ค
โโโ test_client.py # API ํ
์คํธ ํด๋ผ์ด์ธํธ
โโโ test_gradcam_visual.py # GradCAM ์๊ฐํ ํ
์คํธ ํด๋ผ์ด์ธํธ
โโโ requirements.txt # Python ์์กด์ฑ ํจํค์ง
โโโ .env.example # ํ๊ฒฝ ๋ณ์ ์์ ํ์ผ
โโโ .gitignore # Git ์ ์ธ ํ์ผ ๋ชฉ๋ก
โโโ models/ # PyTorch ๋ชจ๋ธ ํ์ผ ์ ์ฅ์
โ โโโ README.md
โโโ uploads/ # ์
๋ก๋๋ ์ด๋ฏธ์ง ์์ ์ ์ฅ์
โ โโโ README.md
โโโ .github/
โโโ copilot-instructions.md
- Python 3.8 ์ด์
- ํ์ํ Python ํจํค์ง๋ค (requirements.txt ์ฐธ์กฐ)
pip install -r requirements.txtcp .env.example .env
# .env ํ์ผ์ ํธ์งํ์ฌ ์ค์ ๊ฐ๋ค์ ์กฐ์ ํ์ธ์PyTorch ๋ชจ๋ธ ํ์ผ(20251006_212412_best_efficientnet.pth)์ models/ ๋๋ ํ ๋ฆฌ์ ๋ฐฐ์นํ์ธ์.
python app.pypython app_simple.py์๋ฒ๊ฐ ์์๋๋ฉด ๋ค์ ์ฃผ์์์ ์ ๊ทผํ ์ ์์ต๋๋ค:
- ๋ก์ปฌ: http://localhost:5000
- ๋คํธ์ํฌ: http://0.0.0.0:5000
GET /์๋ต ์์:
{
"status": "healthy",
"message": "์ง๋ณ์ง๋จ AI ์๋ฒ๊ฐ ์ ์ ์๋ ์ค์
๋๋ค.",
"model_loaded": true
}POST /diagnose
Content-Type: multipart/form-data์์ฒญ ํ๋ผ๋ฏธํฐ:
image: ์ง๋จํ ์ด๋ฏธ์ง ํ์ผ
์๋ต ์์:
{
"results": [
{
"class": "์ ์",
"probability": "95.20%"
},
{
"class": "ํผ๋ถ์ผ",
"probability": "3.15%"
}
]
}POST /api/diagnosis/{model_name}์์ฒญ ํ๋ผ๋ฏธํฐ:
file: ์ง๋จํ ์ด๋ฏธ์ง ํ์ผuserId: ์ฌ์ฉ์ IDgradcam: "true"๋ก ์ค์ ํ๋ฉด GradCAM ๊ฒฐ๊ณผ ํฌํจclassIndex: (์ ํ์ฌํญ) ํน์ ํด๋์ค์ ๋ํ GradCAM ์์ฑ
์๋ต ์์:
{
"results": [
{
"class": "ํผ๋ถ์ผ",
"probability": "87.30%"
}
],
"gradcam": {
"targetIndex": 1,
"score": 0.8730,
"original_base64": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...",
"heatmap_base64": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...",
"overlay_base64": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."
}
}POST /api/diagnosis/{model_name}/gradcam์์ฒญ ํ๋ผ๋ฏธํฐ:
file: ์ง๋จํ ์ด๋ฏธ์ง ํ์ผuserId: ์ฌ์ฉ์ IDclassIndex: (์ ํ์ฌํญ) ํน์ ํด๋์ค์ ๋ํ GradCAM ์์ฑ
์๋ต: ์์ ๋์ผํ ํ์์ผ๋ก ํญ์ GradCAM ๊ฒฐ๊ณผ ํฌํจ
GradCAM(Gradient-weighted Class Activation Mapping)์ AI ๋ชจ๋ธ์ด ์ด๋ฏธ์ง์ ์ด๋ ๋ถ๋ถ์ ๋ณด๊ณ ํ๋จ์ ๋ด๋ ธ๋์ง ์๊ฐ์ ์ผ๋ก ๋ณด์ฌ์ฃผ๋ ๊ธฐ์ ์ ๋๋ค.
-
original_base64: ์ ๋ก๋ํ ์๋ณธ ์ด๋ฏธ์ง
- ๋ถ์ ๋์์ด ๋ ์๋ ์ด๋ฏธ์ง
-
heatmap_base64: ์ดํ์ ๋งต (ํํธ๋งต)
- ๋นจ๊ฐ์ ์์ญ: AI๊ฐ ์ค์ํ๊ฒ ๋ณธ ๋ถ๋ถ (๋์ ๊ด์ฌ๋)
- ํ๋์ ์์ญ: AI๊ฐ ๋ ์ค์ํ๊ฒ ๋ณธ ๋ถ๋ถ (๋ฎ์ ๊ด์ฌ๋)
-
overlay_base64: ์ค๋ฒ๋ ์ด ์ด๋ฏธ์ง
- ์๋ณธ ์ด๋ฏธ์ง ์์ ํํธ๋งต์ ํฌ๋ช ํ๊ฒ ๊ฒน์น ๊ฒฐ๊ณผ
- ์ค์ ๋ณ๋ณ ์์น์ AI ํ๋จ ์์ญ ๋น๊ต ๊ฐ๋ฅ
import requests
import base64
from PIL import Image
from io import BytesIO
# GradCAM API ํธ์ถ
response = requests.post('http://localhost:5000/api/diagnosis/efficientnet/gradcam',
files={'file': ('image.jpg', open('image.jpg', 'rb'))},
data={'userId': 'user123'})
if response.status_code == 200:
result = response.json()
gradcam = result['gradcam']
# Base64 ์ด๋ฏธ์ง๋ฅผ ํ์ผ๋ก ์ ์ฅ
for img_type in ['original', 'heatmap', 'overlay']:
b64_data = gradcam[f'{img_type}_base64']
img_data = base64.b64decode(b64_data)
with open(f'{img_type}.png', 'wb') as f:
f.write(img_data)GET /model/info์๋ต ์์:
{
"model_loaded": true,
"device": "cpu",
"model_path": "models/20251006_212412_best_efficientnet.pth"
}python test_client.pypython test_gradcam_visual.py์ด ํ ์คํธ๋ ๋ค์๊ณผ ๊ฐ์ ๊ฒฐ๊ณผ๋ฅผ ์์ฑํฉ๋๋ค:
gradcam_results/diagnosis_original.png: ์๋ณธ ์ด๋ฏธ์งgradcam_results/diagnosis_heatmap.png: GradCAM ํํธ๋งตgradcam_results/diagnosis_overlay.png: ์๋ณธ + ํํธ๋งต ์ค๋ฒ๋ ์ด
python test_acne_client.pyconfig.py ํ์ผ์์ ๋ค์ ์ค์ ๋ค์ ์กฐ์ ํ ์ ์์ต๋๋ค:
MAX_CONTENT_LENGTH: ์ ๋ก๋ ํ์ผ ์ต๋ ํฌ๊ธฐ (๊ธฐ๋ณธ: 16MB)MODEL_PATH: PyTorch ๋ชจ๋ธ ํ์ผ ๊ฒฝ๋กALLOWED_EXTENSIONS: ํ์ฉ๋ ์ด๋ฏธ์ง ํ์ผ ํ์ฅ์IMAGE_SIZE: ๋ชจ๋ธ ์ ๋ ฅ ์ด๋ฏธ์ง ํฌ๊ธฐ (๊ธฐ๋ณธ: 224x224)
ํ์ฌ ๋ชจ๋ธ์ ๋ค์๊ณผ ๊ฐ์ ํผ๋ถ ์งํ์ ๋ถ๋ฅํฉ๋๋ค:
- ์ ์ (Class ID: 0)
- ํผ๋ถ์ผ (Class ID: 1)
- ์ต์ง (Class ID: 2)
- ๊ฑด์ (Class ID: 3)
- ๊ธฐํ ํผ๋ถ์งํ (Class ID: 4)
- ์๋ฃ์ฉ ์ฃผ์: ์ด ์์คํ ์ ์๋ฃ ์ ๋ฌธ๊ฐ์ ์ง๋จ์ ๋์ฒดํ์ง ์์ต๋๋ค.
- ๊ฐ๋ฐ ์๋ฒ: Flask ๋ด์ฅ ์๋ฒ๋ ๊ฐ๋ฐ์ฉ์ ๋๋ค. ํ๋ก๋์ ํ๊ฒฝ์์๋ Gunicorn, uWSGI ๋ฑ์ ์ฌ์ฉํ์ธ์.
- ๋ชจ๋ธ ํ์ผ: ์ฉ๋์ด ํฐ ๋ชจ๋ธ ํ์ผ์ Git์ ์ปค๋ฐํ์ง ๋ง์ธ์.
- ๋ณด์: ํ๋ก๋์ ํ๊ฒฝ์์๋ ์ ์ ํ ์ธ์ฆ ๋ฐ ๋ณด์ ์ค์ ์ ์ถ๊ฐํ์ธ์.
VS Code์์ ๊ฐ๋ฐํ ๋:
- Python ํ์ฅ ํ๋ก๊ทธ๋จ ์ค์น
- Pylance ํ์ฅ ํ๋ก๊ทธ๋จ ์ค์น
- ํฐ๋ฏธ๋์์
python app.py์คํ ๋๋ VS Code ์์ ์ฌ์ฉ
์ด ํ๋ก์ ํธ๋ ์๋ฃ AI ์ฐ๊ตฌ ๋ฐ ๊ฐ๋ฐ ๋ชฉ์ ์ผ๋ก ์ ์๋์์ต๋๋ค.
๋ฒ๊ทธ ๋ฆฌํฌํธ, ๊ธฐ๋ฅ ์ ์, ํ ๋ฆฌํ์คํธ๋ฅผ ํ์ํฉ๋๋ค!
๊ฐ๋ฐ์: SkinSeal AI Team
๋ฒ์ : 1.0.0
๋ง์ง๋ง ์
๋ฐ์ดํธ: 2025๋
10์ 6์ผ