ํ๊ตญ์ด ์๋ฌผ ํด์ถฉ ๋ถ๋ฅ๊ธฐ โ RunPod ๋ฐฐํฌ ๋ฒ๋ค
WizWix/kor-pest-detector LoRA ์ด๋ํฐ์ RunPod ์ปจํ ์ด๋์์ ๋น ๋ฅด๊ฒ ์๋ฒ๋ฅผ ๊ธฐ๋ํ๊ธฐ ์ํ ๋ชจ๋ ๋ฐฐํฌ ์คํฌ๋ฆฝํธ๋ฅผ ํ ์ ์ฅ์์ ๋ฌถ์์ต๋๋ค. ํ๋๋ฅผ ์์ฃผ ์์ฑยท์ข ๋ฃํ๋ ์ด์ ํจํด์ ๋ง์ถฐ ์ค๊ณ๋์์ต๋๋ค.
| ํญ๋ชฉ | ๊ฐ |
|---|---|
| ๊ฒ์ฆ ์ ํ๋ (1,535์ํ) | 99.48 % (์ถ์ฒ: WizWix evaluation) |
| ํด๋์ค ์ | 20 (์ ์ + 19์ข ํด์ถฉ) |
| VRAM (4-bit) | ์ฝ 8.7 GB |
| ๋์คํฌ (๋ฒ ์ด์ค + ์ด๋ํฐ) | ์ฝ 19 GB |
| ์ฝ๋ ๋ถํธ (๋ชจ๋ธ ์บ์ ์์) | ์ฝ 8 ~ 10๋ถ |
| ์ ๋ถํธ (HF ์บ์ ๋ณด์กด ์) | ์ฝ 90์ด |
์ค๊ณ ์๋
์ด ๋ฒ๋ค์ ๋ค์ ์๋๋ฆฌ์ค๋ฅผ ์ํด ๋ง๋ค์ด์ก์ต๋๋ค:
๋น์ฉ ์ ๊ฐ์ ์ํด RunPod ํ๋๋ฅผ ์์ฃผ ์ผ๊ณ ๋๋ ํ๊ฒฝ. ํ๋๋ ๋ณผ๋ฅจ์ด ์๊ฑฐ๋, ์ปจํ ์ด๋ ๋์คํฌ๊ฐ ๋งค๋ฒ ์ด๊ธฐํ๋๋ ์ํฉ.
๋ฐ๋ผ์ ๋ชจ๋ ์์กด์ฑยท์คํฌ๋ฆฝํธยท์ด๋ํฐ ๊ฐ์ค์น๋ฅผ ์ด ์ ์ฅ์ ํ๋๋ก ํ์ด์, git clone โ bash restart_server.sh ๋ ์ค์ด๋ฉด ์ด๋์๋ ์๋ฒ๊ฐ ๋จ๋๋ก ํ์ต๋๋ค.
๋น ๋ฅธ ์์ (RunPod)
1. ํ๋ ์ฌ์
| ํญ๋ชฉ | ๊ถ์ฅ๊ฐ |
|---|---|
| GPU | VRAM 8 GB ์ด์ (RTX 3060 12GB, 4070, RTX 2000 Ada ๋ฑ) |
| ์ปจํ ์ด๋ ๋์คํฌ | 30 GB ์ด์ (๋ชจ๋ธ ์บ์ ์ฝ 19 GB + ํจํค์ง ์ฝ 4 GB) |
| ๋ฒ ์ด์ค ์ด๋ฏธ์ง | PyTorch 2.8 + CUDA 12.8 + Python 3.12 (RunPod ๊ณต์ PyTorch ํ ํ๋ฆฟ ๊ถ์ฅ) |
| HTTP ํฌํธ | 8888 (RunPod ์ JupyterLab ๊ธฐ๋ณธ ํฌํธ์ ๋์ผํ๋ฏ๋ก ๋ณ๋ ์ถ๊ฐ ๋ ธ์ถ ๋ถํ์) |
โ ํฌํธ 8888 ์ RunPod ์ปจํ ์ด๋์์ ๊ธฐ๋ณธ์ ์ผ๋ก JupyterLab ์ด ์ ์ ํฉ๋๋ค. ๋ณธ ๋ฒ๋ค์
restart_server.sh๋ ์์ ์ JupyterLab ์ ์ข ๋ฃํ๊ณ 8888 ์ ์ ์ ํฉ๋๋ค. JupyterLab ์ด ํ์ํ๋ฉด ๋ค๋ฅธ ํฌํธ๋ก ์ถ๊ฐ ๋ ธ์ถํ์ธ์.
2. ์ค์น ๋ฐ ๊ธฐ๋ (ํ ๋ฒ์)
SSH ๋๋ ์น ํฐ๋ฏธ๋์์ ๋จ ํ ์ค:
mkdir -p /workspace/deploy && cd /workspace/deploy && \
wget -q https://huggingface.co/pfox1995/pest-detector-runpod/resolve/main/restart_server.sh && \
bash restart_server.sh
์ด ํ ์ค์ด ์๋ ์ฒ๋ฆฌํฉ๋๋ค:
restart_server.sh๋ง ๋จผ์ ๋ฐ์ (5 KB)- ์คํฌ๋ฆฝํธ๊ฐ
huggingface_hub.snapshot_download์ผ๋ก ๋๋จธ์ง ๋ฒ๋ค (์ด๋ํฐ ๊ฐ์ค์น ~693 MB, ํ ํฌ๋์ด์ ~20 MB, server.py ๋ฑ) ์ ๊ฐ์ ๋๋ ํ ๋ฆฌ์ ๋ฐ์ - pip ์ค์น โ ๋ฒ ์ด์ค ๋ชจ๋ธ ๋ค์ด๋ก๋ โ ์๋ฒ ๊ธฐ๋
โ
git clone์ ๊ถ์ฅํ์ง ์์ต๋๋ค. HuggingFace ์ ๋์ฉ๋ ํ์ผ์ Git LFS ๋ฅผ ์ฌ์ฉํ๋ฏ๋ก ์ผ๋ฐgit clone์ 134 ๋ฐ์ดํธ์ง๋ฆฌ ํฌ์ธํฐ ํ์ผ ๋ง ๋ฐ์์ต๋๋ค. ๋ณธ ์คํฌ๋ฆฝํธ๋ ์ด ๊ฒฝ์ฐ๋ฅผ ์๋ ๊ฐ์งํ๊ณhuggingface_hub๋ก ๋ค์ ๋ฐ์ง๋ง, ์๊ฐ์ด ๋ ๋ฐฐ๋ก ๋ญ๋๋ค. ์์ wget ํ ์ค์ด ๊ฐ์ฅ ๊น๋ํฉ๋๋ค.
restart_server.sh ๊ฐ ์๋ ์ฒ๋ฆฌํ๋ ๋จ๊ณ:
| ๋จ๊ณ | ์์ ์๊ฐ | ๋ด์ฉ |
|---|---|---|
| 1. Python ์์กด์ฑ ์ค์น | ~3๋ถ | unsloth, peft, fastapi, bitsandbytes, flash-linear-attention ๋ฑ |
2. causal_conv1d ์ฌ์ ๋น๋ wheel ์ค์น |
~30์ด | torch 2.8 + cu12 + py312 ์ฉ |
3. JupyterLab ์ข
๋ฃ + tmux pest ์ธ์
๊ธฐ๋ |
~5์ด | ํฌํธ 8888 ์ ์ |
| 4. ๋ฒ ์ด์ค ๋ชจ๋ธ ๋ค์ด๋ก๋ | ~4 ~ 5๋ถ | unsloth/Qwen3.5-9B ์ฝ 19 GB (HF cache ๋ฏธ์กด์ฌ ์) |
| 5. LoRA ์ด๋ํฐ ๋ถ์ฐฉ | ~5์ด | ๋ฒ๋ค ๋ด๋ถ ํ์ผ ์ง์ ์ฌ์ฉ (์ฌ๋ค์ด๋ก๋ ์์) |
| 6. Triton JIT ์๋ฐ์ | (์ฒซ ํธ์ถ ์ ~10์ด) | ์ฒซ /classify ํธ์ถ์์๋ง ๋ฐ์ |
3. ๋์ ํ์ธ
์ค์น๊ฐ ๋๋๋ฉด RunPod ๊ฐ ์๋์ผ๋ก ๊ณต๊ฐ ํ๋ก์ URL ์ ๋ถ์ฌํฉ๋๋ค:
curl https://<POD_ID>-8888.proxy.runpod.net/health
# {"status":"ok","model_loaded":true}
๋ธ๋ผ์ฐ์ ๋ก https://<POD_ID>-8888.proxy.runpod.net/ ์ ์ ์ํ๋ฉด ํ๊ตญ์ด ์
๋ก๋ UI ๊ฐ ํ์๋ฉ๋๋ค.
๋งค๋ฒ ๋๊ณ ์ผ๋ ์ด์ ๊ฐ์ด๋
RunPod ํ๋์ ์ปจํ ์ด๋๋ฅผ ์ฌ์์ยท์ฌ์์ฑํ๋ฉด:
- โ ์ปจํ
์ด๋ ๋์คํฌ๊ฐ ์ด๊ธฐํ๋จ (
/workspace๊ฐ ๋ณผ๋ฅจ์ด ์๋๋ฉด ํจ๊ป ์ฌ๋ผ์ง) - โ ์ค์น๋ pip ํจํค์ง๊ฐ ๋ชจ๋ ์ฌ๋ผ์ง
- โ ๋ชจ๋ธ ์บ์ (
~/.cache/huggingface) ๊ฐ ์ฌ๋ผ์ง โ ์ด๊ฒ ์ฝ๋ ๋ถํธ์ ๊ฐ์ฅ ํฐ ๋น์ฉ
๋ฐ๋ผ์ ๋งค๋ฒ ์ ๋น ๋ฅธ ์์ 2๋ฒ ์ ์ฐจ๋ฅผ ๋ค์ ์คํํ๋ฉด ๋ฉ๋๋ค (git clone ๋ถํฐ).
์ฝ๋ ๋ถํธ ๋น์ฉ ์ค์ด๊ธฐ (์ ํ)
| ๋ฐฉ๋ฒ | ์ ๊ฐ ํจ๊ณผ | ์ถ๊ฐ ๋น์ฉ |
|---|---|---|
/workspace ์ RunPod ๋คํธ์ํฌ ๋ณผ๋ฅจ ๋ง์ดํธ |
์ฝ๋ ๋ถํธ โ ์ฝ 90์ด | ๋ณผ๋ฅจ ์๋๋ฃ (์ ์ฝ GB๋น $0.07, 30 GB โ $2.1/์) |
| ์ฌ์ ๋น๋ Docker ์ด๋ฏธ์ง ์ฌ์ฉ | pip ๋จ๊ณ ์๋ต | ์ด๋ฏธ์ง ๋น๋/์ ์ง ๋ถ๋ด |
unsloth/Qwen3.5-9B-bnb-4bit ์ฌ์ฉ |
๋ฒ ์ด์ค ๋ค์ด๋ก๋ 19 GB โ 5 GB | BASE_MODEL ํ๊ฒฝ๋ณ์๋ก ๋ณ๊ฒฝ ๊ฐ๋ฅ, ์ ํ๋ ๋์ผ |
๊ฐ์ฅ ๋น์ฉ ๋๋น ํจ๊ณผ๊ฐ ์ข์ ์ต์ ์ ๋ฒ ์ด์ค ๋ชจ๋ธ์ 4-bit ์ฌ์ ์์ํ ๋ฒ์ ์ผ๋ก ๋ณ๊ฒฝํ๋ ๊ฒ์ ๋๋ค. ์ฝ๋ ๋ถํธ ์๊ฐ์ด ์ฝ ์ ๋ฐ(8๋ถ โ 4๋ถ)์ผ๋ก ์ค๊ณ ์ถ๊ฐ ๋น์ฉ๋ ์์ต๋๋ค.
API
์๋ฒ๋ FastAPI ๊ธฐ๋ฐ์ด๋ฉฐ 5๊ฐ ์๋ํฌ์ธํธ๋ฅผ ์ ๊ณตํฉ๋๋ค.
| ๋ฉ์๋ | ๊ฒฝ๋ก | ์ค๋ช |
|---|---|---|
| GET | /health |
{"status":"ok","model_loaded":true} |
| GET | /classes |
20๊ฐ ํด๋์ค ๋ชฉ๋ก๊ณผ ๊ฐ์ |
| GET | / |
๋ธ๋ผ์ฐ์ ์ฉ ํ๊ตญ์ด ์ ๋ก๋ ํ์ด์ง |
| POST | /classify |
multipart file=... ์
๋ก๋ โ ์์ธก ๊ฒฐ๊ณผ |
| POST | /classify_b64 |
JSON {"image":"<base64>"} โ ์์ธก ๊ฒฐ๊ณผ |
์๋ต ์์
curl -F file=@pest.jpg https://<POD_ID>-8888.proxy.runpod.net/classify
# {"pred":"๊ฒ๊ฑฐ์ธ๋ฏธ๋ฐค๋๋ฐฉ","raw":"๊ฒ๊ฑฐ์ธ๋ฏธ๋ฐค๋๋ฐฉ","elapsed_s":2.3}
ํ์ด์ฌ ํด๋ผ์ด์ธํธ ์์
import requests
resp = requests.post(
"https://<POD_ID>-8888.proxy.runpod.net/classify",
files={"file": open("pest.jpg", "rb")},
timeout=60,
)
print(resp.json()["pred"]) # ํ๊ตญ์ด ํด๋์ค๋ช
ํ๊ฒฝ๋ณ์
bash restart_server.sh ์คํ ์ ํ๊ฒฝ๋ณ์๋ก ๋์์ ๋ณ๊ฒฝํ ์ ์์ต๋๋ค.
| ๋ณ์ | ๊ธฐ๋ณธ๊ฐ | ์ค๋ช |
|---|---|---|
PORT |
8888 |
์๋ฒ ์ฒญ์ทจ ํฌํธ (RunPod ์์ ์ธ๋ถ ๋ ธ์ถ๋์ด์ผ ํจ) |
ADAPTER |
(์๋ ๊ฐ์ง) | ๋ณธ ๋ฒ๋ค ๋๋ ํ ๋ฆฌ ์์ adapter_config.json ์ด ์์ผ๋ฉด ๊ทธ ๊ฒฝ๋ก, ์์ผ๋ฉด pfox1995/pest-detector-runpod HF ์ ์ฅ์ |
BASE_MODEL |
unsloth/Qwen3.5-9B |
๋ฒ ์ด์ค VLM. 4-bit ์ฌ์ ์์ํ ๋ณํ์ผ๋ก ๋ณ๊ฒฝํ๋ ค๋ฉด unsloth/Qwen3.5-9B-bnb-4bit |
LOAD_IN_4BIT |
true |
bnb NF4 4-bit ๋ก ๋ก๋. false ๋ฉด FP16 (VRAM ์ฝ 19.5 GB ํ์) |
HF_TOKEN |
(์์) | private ์ ์ฅ์ ์ฌ์ฉ ์์๋ง ํ์ |
PUBLIC_URL |
์๋ ๊ฐ์ง | ์ถ๋ ฅ์ฉ ๊ณต๊ฐ URL. RunPod ์ RUNPOD_POD_ID ํ๊ฒฝ๋ณ์์์ ์๋ ์ถ๋ก |
# ์: FP16 ๋ก ๋์ฐ๊ธฐ (VRAM 20 GB ์ด์ GPU)
LOAD_IN_4BIT=false bash restart_server.sh
# ์: ๋ค๋ฅธ ํฌํธ๋ก
PORT=9000 bash restart_server.sh
# ์: ๋ค๋ฅธ ์ด๋ํฐ๋ก (ํธํ๋๋ ๊ฒฝ์ฐ๋ง)
ADAPTER=๋ค๋ฅธ๊ณ์ /๋ค๋ฅธ์ด๋ํฐ bash restart_server.sh
ํด๋์ค ๋ชฉ๋ก (20๊ฐ)
์ ์ ์ ํฌํจํ 20๊ฐ ํ๊ตญ์ด ํด๋์ค:
์ ์, ๊ฒ๊ฑฐ์ธ๋ฏธ๋ฐค๋๋ฐฉ, ๊ฝ๋
ธ๋์ด์ฑ๋ฒ๋ , ๋ด๋ฐฐ๊ฐ๋ฃจ์ด, ๋ด๋ฐฐ๊ฑฐ์ธ๋ฏธ๋๋ฐฉ,
๋ด๋ฐฐ๋๋ฐฉ, ๋๋๋๋ฐฉ, ๋จน๋
ธ๋ฆฐ์ฌ, ๋ชฉํ๋ฐ๋๋ช
๋๋ฐฉ, ๋ฌด์๋ฒ,
๋ฐฐ์ถ์ข๋๋ฐฉ, ๋ฐฐ์ถํฐ๋๋น, ๋ฒผ๋ฃฉ์๋ฒ๋ , ๋ณต์ญ์ํน์ง๋ง๋ฌผ, ์ฉ๋ฉ๋๋ฌด๋
ธ๋ฆฐ์ฌ,
์ด๋๊ฑฐ์ธ๋ฏธ๋๋ฐฉ, ํฐ28์ ๋ฐ์ด๋ฌด๋น๋ฒ๋ , ํฑ๋ค๋ฆฌ๊ฐ๋ฏธํ๋ฆฌ๋
ธ๋ฆฐ์ฌ, ํ๋ฐค๋๋ฐฉ, ํ๋น๋จ๋
ธ๋ฆฐ์ฌ
/classes ์๋ํฌ์ธํธ๊ฐ ํญ์ ์บ๋
ธ๋์ปฌ ์ ๋ ฌ๋ ๋ชฉ๋ก์ ๋ฐํํฉ๋๋ค (์ ๋ ฌ์ ํ๊ธ ์ฌ์ ์, ์ ์ ์ ํด๋์ค ์ดํ ์์์๋ ์ํ๋ฒณ ์์๋๋ก ๋ค์ด๊ฐ).
ํธ๋ฌ๋ธ์ํ
์๋ฒ๊ฐ ์ ๋ธ / /health ๊ฐ 200 ์ ๋ณด๋
# tmux ์ธ์
๋ก๊ทธ ํ์ธ
tmux capture-pane -t pest -p | tail -50
# ๋๋
tail -100 /workspace/pest_server.log
/classify ๊ฐ adgeadge... ๊ฐ์ ์ฐ๋ ๊ธฐ ํ
์คํธ๋ฅผ ๋ฐํ
merge_and_unload() ๋ฅผ ํธ์ถํ๊ฑฐ๋ transformers.AutoModelForImageTextToText ๋ก ๋ฒ ์ด์ค๋ฅผ ๋ก๋ํ ๊ฒฝ์ฐ ๋ฐ์ํฉ๋๋ค. ๋ฐ๋์ unsloth.FastVisionModel.from_pretrained + peft.PeftModel.from_pretrained ๋ฐํ์ ํ
์ผ๋ก๋ง ๋ก๋ํ์ธ์. ๋ณธ ๋ฒ๋ค์ server.py ๋ ์ด๋ฏธ ์ฌ๋ฐ๋ฅด๊ฒ ์ค์ ๋์ด ์์ต๋๋ค.
CUDA OOM
LOAD_IN_4BIT=true ๋ก ๋ค์ ๋์ฐ์ธ์ (๊ธฐ๋ณธ๊ฐ). ๊ทธ๋๋ ๋ถ์กฑํ๋ฉด GPU ๋ฅผ ๋ ํฐ ๊ฒ์ผ๋ก ๋ณ๊ฒฝํด์ผ ํฉ๋๋ค (FP16 ์ ์ฝ 20 GB, 4-bit ์ ์ฝ 9 GB ํ์).
์ฒซ ํธ์ถ์ด ๋๋ฌด ์ค๋ ๊ฑธ๋ฆผ (10์ด+)
์ ์์ ๋๋ค. Triton JIT ๊ฐ Gated DeltaNet ์ปค๋์ ์ปดํ์ผํฉ๋๋ค. ๋ ๋ฒ์งธ ํธ์ถ๋ถํฐ๋ ์ฝ 2์ด์ ๋๋ค. JIT ์บ์๋ ์ปจํ ์ด๋ ์ฌ์์ ์ ์ฌ๋ผ์ง๋๋ค.
causal_conv1d ๋น๋ ์คํจ
์ฌ์ ๋น๋๋ wheel ์ด ์์ผ๋ restart_server.sh ์์ ์๋ ์ค์นํฉ๋๋ค. ๋ง์ฝ ์ง์ ๋น๋ํ๋ฉด 9๊ฐ GPU ์ํคํ
์ฒ ์ปดํ์ผ๋ก OOM ์ด ๋ฐ์ํฉ๋๋ค.
GGUF / Ollama / llama.cpp ๋ก ๋ฐฐํฌ ๋ถ๊ฐ
๋ณธ ์ด๋ํฐ๋ Qwen3.5 ์ Gated DeltaNet ๋ชจ๋ (linear_attn.in_proj_*) ์ ํ์ต ๋์์ผ๋ก ํฌํจํฉ๋๋ค. convert_hf_to_gguf.py ์ V-row ์์ด์ด LoRA ๋ธํ์ ํธํ๋์ง ์์, GGUF ๋ณํ ํ ์ถ๋ ฅ์ด ํ ํฐ ๋ถ๊ดด (adgeadge...) ๋ฉ๋๋ค.
์์ธ ์์ธ ๋ถ์์ llama.cpp#21125 ์ฐธ๊ณ . ๋ณธ ๋ฒ๋ค์ PEFT ๋ฐํ์ ํ ๋ฐฉ์๋ง ์ฌ์ฉํฉ๋๋ค.
์ถ์ฒ ๋ฐ ๋ผ์ด์ ์ค
| ๊ตฌ์ฑ | ์ถ์ฒ | ๋ผ์ด์ ์ค |
|---|---|---|
| LoRA ์ด๋ํฐ ๊ฐ์ค์น | WizWix/kor-pest-detector | Apache-2.0 (๋ฒ ์ด์ค ๋ชจ๋ธ ๊ธฐ์ค) |
| ๋ฒ ์ด์ค VLM | unsloth/Qwen3.5-9B | Apache-2.0 |
| ํ์ต ๋ฐ์ดํฐ์ | Himedia-AI-01/pest-detection-korean | ๋ฐ์ดํฐ์ ํ์ด์ง ์ฝ๊ด ๋ฐ๋ฆ |
๋ฐฐํฌ ์คํฌ๋ฆฝํธ (server.py, inference.py, restart_server.sh, requirements.txt) |
๋ณธ ์ ์ฅ์ ์์ฑ์ (@pfox1995) | MIT |
๋ณธ ์ ์ฅ์๋ ํ์ต ์์ฒด๋ WizWix ๊ฐ ์ํํ ์ด๋ํฐ๋ฅผ RunPod ๋ฐฐํฌ์ ์ต์ ํํ์ฌ ์ฌํฌ์ฅํ ๋ฒ๋ค์ ๋๋ค. ์ด๋ํฐ ์์ฒด์ ๋ํ ํ์ต ์ธ๋ถ ์ ๋ณดยทํ๊ฐ ๋ฉํธ๋ฆญยทconfusion matrix ๋ฑ์ WizWix/kor-pest-detector ์ evaluation ๋๋ ํ ๋ฆฌ๋ฅผ ์ฐธ๊ณ ํ์ธ์.
๋ณ๊ฒฝ ์ด๋ ฅ
- v1.0 (์ต์ด): WizWix/kor-pest-detector v(time of bundling) + RunPod ๋ฐฐํฌ ์คํฌ๋ฆฝํธ ๋ฒ๋ค
- Downloads last month
- 66