Spaces:
Running
RM-DETECT โ ๊ธฐ์ ์ํคํ ์ฒ ์ค๋ช ์
AI ์์ฑ ํ ์คํธ ํ๋ณ๊ธฐ์ ๋ด๋ถ ๊ตฌ์กฐ, ๋ฐ์ดํฐ ํ๋ฆ, ํผ์ฒ ์ฌ์, ๋ชจ๋ธ, API, ๋ฐฐํฌ๋ฅผ ์ ๋ฆฌํ ๊ธฐ์ ๋ฌธ์์ ๋๋ค. ๊ฐ์๋ README๋ฅผ, ์๋๋ ๊ตฌํ ์ธ๋ถ๋ฅผ ๋ค๋ฃน๋๋ค.
1. ๊ฐ์
RM-DETECT๋ ์ ๋ ฅ ํ ์คํธ๊ฐ ๋๊ท๋ชจ ์ธ์ด๋ชจ๋ธ(LLM)๋ก ์์ฑ๋์ ๊ฐ๋ฅ์ฑ์ ์ถ์ ํ๋ ๋ ๋ฆฝ์ ์ผ๋ก ๊ตฌํํ ํ๋ณ๊ธฐ์ ๋๋ค. ๋ ๊ฐ์ง ์ํธ ๋ณด์์ ์ ํธ๋ฅผ ํ๋์ ๋ถ๋ฅ๊ธฐ๋ก ๊ฒฐํฉํฉ๋๋ค:
- ํ ํฐ ์์ธก ๊ฐ๋ฅ์ฑ(perplexity) โ LLM์ด ๋ง๋ ๊ธ์ ๋ "์์ธก ๊ฐ๋ฅ"ํ๋ค๋, AI ํ ์คํธ ํ์ง ๋ฌธํ(GLTR, DetectGPT ๋ฑ)์์ ํ๋ฆฝ๋ ์๋ฆฌ
- ๋ฌธ์ฒดยทํต๊ณ ๋ถ์(stylometry) โ ์ธ์ด๋ชจ๋ธ ์์ด ๊ณ์ฐํ๋ ๋ฌธ์ฅ ๋ฆฌ๋ฌยท์ดํยท๋ฌธ์ฅ๋ถํธยท์ด๋ฏธ ํน์ง
ํ๊ตญ์ด์ ์์ด๋ฅผ ๋ชจ๋ ์ง์ํ๋ฉฐ, ๋ฌธ์ ์ ์ฒด ์ ์์ ๋ฌธ๋จ๋ณ ์ ์๋ฅผ ๋์์ ์ฐ์ถํฉ๋๋ค. ๋ชจ๋ ์ถ๋ก ์ด ์๋ฒ ๋ด๋ถ์์ ์คํ๋์ด ์ธ๋ถ ์ ๋ฃ API๋ฅผ ํธ์ถํ์ง ์์ต๋๋ค.
2. ์ปดํฌ๋ํธ ๊ตฌ์กฐ
rmdetect/
โโโ app.py # FastAPI ๋ฐฑ์๋ + RMDetector ์ค์ผ์คํธ๋ ์ด์
โโโ aidetect/ # ํ์ง ์์ง (ํ๋ ์์ํฌ ๋
๋ฆฝ)
โ โโโ perplexity.py # โ ํ ํฐ ์์ธก ๊ฐ๋ฅ์ฑ (GPT-2 / KoGPT2)
โ โโโ stylometry.py # โก ๋ฌธ์ฒดยทํต๊ณ ํผ์ฒ (model-free)
โ โโโ langid.py # ์ธ์ด ๊ฐ์ง (Hangul-ratio router)
โ โโโ features.py # โ +โก ๋ณํฉ โ 28์ฐจ์ ๋ฒกํฐ
โ โโโ __init__.py
โโโ ai_detector_model.joblib # ํ์ต๋ ๋ถ๋ฅ๊ธฐ (StandardScaler + LogReg)
โโโ static/ # ๋จ์ผ ํ์ด์ง ์น UI
โ โโโ index.html
โ โโโ app.js
โ โโโ style.css
โโโ requirements.txt
โโโ run.sh # ๋ก์ปฌ ์คํ ์คํฌ๋ฆฝํธ
โโโ Dockerfile # ์ปจํ
์ด๋/HF Spaces ๋ฐฐํฌ
๊ณ์ธต์ ์ธ ๊ฒน์ ๋๋ค: UI(static) โ API(app.py) โ ์์ง(aidetect). ์์ง์ ์น ํ๋ ์์ํฌ์ ์์กดํ์ง ์์ผ๋ฏ๋ก CLIยท๋ฐฐ์นยท๋ค๋ฅธ ์๋น์ค์์๋ ๊ทธ๋๋ก ์ฌ์ฌ์ฉํ ์ ์์ต๋๋ค.
3. ์์ฒญ ์ฒ๋ฆฌ ํ๋ฆ (POST /detect)
- ์ธ์ด ๊ฐ์ง โ
langid.detect_lang()๊ฐ ํ๊ธ/๋ผํด ๋ฌธ์ ๋น์จ๋กko/enํ์ (์์ฒญ์lang์ด ๋ช ์๋๋ฉด ๊ทธ๋๋ก ์ฌ์ฉ). - ๋ฌธ๋จ ๋ถํ โ ๋น ์ค ๊ธฐ์ค์ผ๋ก ๋ฌธ๋จ์ ๋๋๋, ๊ฐ ๋ฌธ๋จ์ ์๋ฌธ ๋ฌธ์ ์คํ์
(start, end)์ ๋ณด์กด. ์ด ์คํ์ ๋๋ถ์ UI๊ฐ ์๋ฌธ์ ์ ํํ ๊ตฌ๊ฐ์ ํ์ด๋ผ์ดํธํ ์ ์์. - ํผ์ฒ ์ถ์ถ โ ๋ฌธ์ ์ ์ฒด์ ๊ฐ ๋ฌธ๋จ์ ๋ํด
features.full_features()๋ฅผ ํธ์ถํด 28์ฐจ์ ๋ฒกํฐ๋ฅผ ๋ง๋ฆ. - ๋ถ๋ฅ โ
StandardScaler โ LogisticRegressionํ์ดํ๋ผ์ธ์ด AI ํ๋ฅ ์ ์ฐ์ถํ๊ณ , ํ์ ๋ฐด๋์ ๋งคํ. - ๊ธฐ์ฌ ์ ํธ ๊ณ์ฐ โ ๊ฐ ํผ์ฒ์ ํ์คํ ๊ฐ ร ํ๊ท ๊ณ์๋ก "์ด ํ์ ์ AI/์ธ๊ฐ ์ชฝ์ผ๋ก ๋ฏผ ์์ ์ ํธ"๋ฅผ ์ถ์ถ.
- ์๋ต ์ง๋ ฌํ โ ๋ฌธ์ ์ ์ + ๋ฌธ๋จ ๋ฐฐ์ด(์คํ์ ยทํ๋ฅ ยทํ์ ยทflaggedยท์์ ์ ํธ)์ JSON์ผ๋ก ๋ฐํ.
๋ฌธ๋จ์ด paragraph_min_chars(๊ธฐ๋ณธ 30์)๋ณด๋ค ์งง์ผ๋ฉด low_confidence=true๋ก ํ์ํ๊ณ flagged ๋์์์ ์ ์ธํฉ๋๋ค.
4. ์ ํธ ๊ณ์ด โ โ ํ ํฐ ์์ธก ๊ฐ๋ฅ์ฑ (perplexity.py)
์์ causal LM์ ์ธ์ด๋ณ๋ก ๋ก๋ํฉ๋๋ค: ์์ด GPT-2, ํ๊ตญ์ด KoGPT2(skt/kogpt2-base-v2), ๊ฐ๊ฐ ~125M ํ๋ผ๋ฏธํฐ.
- ์๋ฆฌ โ LLM์ ๋ค์ ํ ํฐ์ผ๋ก ๋์ ํ๋ฅ ์ ํ ํฐ์ ๊ณ ๋ฅด๋ฏ๋ก, ๊ธฐ๊ณ ์์ฑ ํ ์คํธ๋ perplexity๊ฐ ๋ฎ๊ณ ๋ชจ๋ธ์ด ์์๋ก ๊ผฝ์์ ํ ํฐ์ ๋น์จ(top-k ์ ์ค๋ฅ )์ด ๋์. ์ธ๊ฐ ๊ธ์ "burstier"ํด์ ๋ฎ์ ํ๋ฅ ์ ๋จ์ด๋ฅผ ๋ ์์ฃผ ์.
- ์ฐ์ถ ํผ์ฒ (6๊ฐ):
ppl,log_ppl,mean_logprob,std_logprob,median_logprob,topk_hit_rate - ๊ธด ๋ฌธ์ ์ฒ๋ฆฌ โ ์ปจํ ์คํธ ์ฐฝ(โค1024 ํ ํฐ)์ ๋๋ ํ ์คํธ๋ sliding window๋ก ์ฒ๋ฆฌํ๊ณ , ๊ฒน์น๋ ๊ตฌ๊ฐ์ ๋ง์คํนํด ์ค๋ณต ์ง๊ณ๋ฅผ ๋ฐฉ์ง.
- ๋ชจ๋ธ ๋ก๋ฉ โ ๋ก์ปฌ
models/gpt2ยทmodels/kogpt2๊ฐ ์์ผ๋ฉด ์คํ๋ผ์ธ์ผ๋ก ๋ก๋, ์์ผ๋ฉด HuggingFace ํ๋ธ์์ ์๋ ๋ค์ด๋ก๋(์: HF Spaces ์ฒซ ์คํ).
5. ์ ํธ ๊ณ์ด โก โ ๋ฌธ์ฒดยทํต๊ณ (stylometry.py)
์ธ์ด๋ชจ๋ธ์ด ํ์ ์๋ 22๊ฐ ํผ์ฒ. ํ๊ตญ์ดยท์์ด ๋ชจ๋์ ๋์ํ๋ ์ ๊ท์ ๊ธฐ๋ฐ ๋ฌธ์ฅ ๋ถํ ์ ์ฌ์ฉํฉ๋๋ค.
| ๊ทธ๋ฃน | ํผ์ฒ | ์ ํธ ๋ฐฉํฅ |
|---|---|---|
| ๋ฌธ์ฅ ๋ฆฌ๋ฌ | burstiness, cv_sent_len, std_sent_len, mean_sent_len, mean_succ_diff, n_sents |
์ธ๊ฐ์ ๋ฌธ์ฅ ๊ธธ์ด ๋ณ๋์ด ํผ; AI๋ ๊ท ์ผ |
| ์ดํ | type_token_ratio, rep_bigram_rate, word_entropy, avg_word_len |
AI๋ ์ ์ ๊ตฌ์กฐ๋ฅผ ๋ฐ๋ณต |
| ๋ฌธ์ฅ๋ถํธ | excl_per100, ques_per100, ellipsis_per100, comma_per100, quote_per100, emoji_per100, punct_variety |
์ธ๊ฐ์ !!, โฆ, ์ด๋ชจ์ง ์ฌ์ฉ โ |
| ๊ตฌ์ด์ฒด | informal_per100 (ใ
ใ
, lol, ์ง์งโฆ) |
์ธ๊ฐ ์ ํธ |
| ์ ์์ด | connective_per100 (์ข
ํฉ์ ์ผ๋ก, ๋ฐ๋ผ์, furthermoreโฆ) |
AI ์ ํธ |
| ํ๊ตญ์ด ์ด๋ฏธ | ko_formal_per100, ko_casual_per100, ko_formal_minus_casual |
๊ฒฉ์์ฒด(ํ์์ต๋๋ค)๋ AI ์ชฝ, ๊ตฌ์ด์ฒด(~ํ์)๋ ์ธ๊ฐ ์ชฝ |
6. ๋ถ๋ฅ๊ธฐ (ai_detector_model.joblib)
- ๊ตฌ์กฐ โ scikit-learn
Pipeline([StandardScaler, LogisticRegression(class_weight="balanced")]) - ์
๋ ฅ โ
FEATURE_ORDER๋ก ๊ณ ์ ๋ 28์ฐจ์ ๋ฒกํฐ (perplexity 6 + stylometry 22) - ์ฑ๋ฅ โ ๋ณด์ ๋ฐ์ดํฐ์ ์์ 5-fold ๊ต์ฐจ๊ฒ์ฆ ์ ํ๋ 97.2%, AUC 0.994 (ํ๊ตญ์ด 100%, ์์ด 93.8%)
- ์ค๋ช ๊ฐ๋ฅ์ฑ โ ์ ํ ๋ชจ๋ธ์ด๋ผ ๊ฐ ํผ์ฒ์ (ํ์คํ ๊ฐ ร ๊ณ์) ๊ธฐ์ฌ๋๋ฅผ ๊ทธ๋๋ก ๋ ธ์ถ. ์ธก์ ๋ ์์ ์ ํธ: ์ธ๊ฐ ์ชฝ์ ๊ตฌ์ด์ฒดยท์ธ์ฉ๋ถํธยท๋ง์ค์ํ ๋ฐ๋์ ๋ฌธ์ฅ burstiness, AI ์ชฝ์ ํ๊ตญ์ด ๊ฒฉ์ ์ด๋ฏธยท๊ธด ๋จ์ดยท๊ท ์ผํ ๋ฌธ์ฅ ๋ฆฌ๋ฌ.
7. ํ์ ๋ฐด๋
| AI ํ๋ฅ | verdict | ๋ฌธ๋จ flagged |
|---|---|---|
| โฅ 0.85 | AI-generated | โ |
| โฅ 0.60 | Likely AI | โ |
| โฅ 0.40 | Mixed | |
| โฅ 0.15 | Likely human | |
| < 0.15 | Human-written |
๋ฌธ๋จ์ ai_probability โฅ 0.60 ์ด๊ณ low_confidence๊ฐ ์๋ ๋ flagged(์์ฌ ์์ญ)๋ก ํ์๋ฉ๋๋ค.
8. API ๋ ํผ๋ฐ์ค
GET /health
{ "status": "ok", "model_loaded": true, "load_error": null, "uptime_s": 159.9, "max_chars": 20000 }
POST /detect
์์ฒญ:
{ "text": "๊ฒ์ฌํ ๊ธ ...", "lang": "ko" }
lang์ ์ ํ("ko" | "en" | ์๋ต ์ ์๋ ๊ฐ์ง). ์๋ต(์์ฝ):
{
"language": "ko",
"overall_ai_probability": 0.50,
"verdict": "Mixed",
"n_paragraphs": 3,
"n_flagged": 1,
"top_features": [ {"feature": "informal_per100", "contribution": -1.17, "direction": "human"} ],
"paragraphs": [
{ "index": 0, "start": 0, "end": 40, "text": "...",
"ai_probability": 0.35, "verdict": "Likely human",
"flagged": false, "low_confidence": false, "top_features": [ ... ] }
],
"elapsed_ms": 2640.3
}
์ค๋ฅ ์๋ต: ๋น ์
๋ ฅ 400 ยท ์๋ชป๋ lang 400 ยท 20000์ ์ด๊ณผ 413 ยท ๋ชจ๋ธ ๋ฏธ๋ก๋ฉ 503.
9. ์น UI (static/)
์์กด์ฑ ์๋ ์์ HTML/CSS/๋ฐ๋๋ผ JS. ํ
์คํธ ์
๋ ฅ โ fetch("/detect") โ ๊ฒฐ๊ณผ ๋ ๋:
- ์ ์ฒด AI ํ๋ฅ ์ SVG ๋๋ ๊ฒ์ด์ง + verdict๋ก ํ์
- ๋ฌธ์ ์์ค ์์ ๊ธฐ์ฌ ์ ํธ๋ฅผ ์นฉ์ผ๋ก ํ์
- ๋ฌธ๋จ์ ํ๋ฅ ์ ๋ฐ๋ผ ์ด๋กโ๋ ธ๋โ๋นจ๊ฐ์ผ๋ก ์์ ๋ฑ๊ธํํ ์นด๋๋ก ์ฌํ, ์นด๋๋ฅผ ํด๋ฆญํ๋ฉด ๊ทธ ๋ฌธ๋จ์ ์์ ์ ํธ๊ฐ ํผ์ณ์ง
- ํ๊ตญ์ดยท์์ด ๋ผ๋ฒจ ๋ณ๊ธฐ, Cmd/Ctrl+Enter ๋จ์ถํค
10. ๋ฐฐํฌ
๋ก์ปฌ
pip install -r requirements.txt
./run.sh # http://127.0.0.1:8000
๋ก์ปฌ models/๊ฐ ์์ผ๋ฉด ์คํ๋ผ์ธ์ผ๋ก ์ฆ์ ๋ก๋, ์์ผ๋ฉด ํ๋ธ์์ ๋ชจ๋ธ์ ๋ฐ์.
Docker / Hugging Face Spaces
Dockerfile์ HF Spaces ๊ท๊ฒฉ(๋น๋ฃจํธ UID 1000, ํฌํธ 7860, HF ์บ์ ๊ฒฝ๋ก)์ ๋ง์ถฐ์ ธ ์์ต๋๋ค. README.md ์๋จ์ YAML ํค๋(sdk: docker, app_port: 7860)๋ก Spaces๊ฐ ์ค์ ์ ์ฝ์ต๋๋ค. ์ปจํ
์ด๋์๋ ์ฝ๋๋ง ๋ด๊ณ , ์ธ์ด๋ชจ๋ธ์ ์ฒซ ์คํ ์ ํ๋ธ์์ ๋ฐ์ ์บ์ํฉ๋๋ค.
11. ํ๊ณ
- ์์ ๋ณด์ ์ (n=36) ๊ณผ LLM์ด ๋ชจ์ฌํ "์ธ๊ฐ" ์ํ โ ํ์์ ์ธ ์ค์ ์ธ๊ฐ ๊ธ(๋ ผ๋ฌธ, ์ ์ ๋ ์๊ธฐ์๊ฐ์)์ ์ค์ ๋ณด๋ค ๋ ์์ฃผ ์คํ๋ ์ ์์.
- ์์ ์ฐธ์กฐ LM(GPT-2/KoGPT2, ~125M) โ ๋ ํฌ๊ฑฐ๋ instruction-tuned ๋ชจ๋ธ์ด๋ฉด perplexity ์ ํธ๊ฐ ๋ ์ ๋ช ํด์ง.
- ํจ๋ฌํ๋ ์ด์ฆ์ ์ทจ์ฝ โ burstinessยท๊ตฌ์ด์ฒด์ ๋ฐ์ํ๋ฏ๋ก, ๊ตฌ์ด์ฒด๋ฅผ ์๊ณ ๋ฌธ์ฅ ๊ธธ์ด๋ฅผ ํฉ๋จ๋ฆฌ๋ "ํด๋จธ๋์ด์ง" ํธ์ง์ด AI ์ ์๋ฅผ ๋ฎ์ถค.
- CPU ์ง์ฐ โ ๋ฉํฐ์ฝ์ด์์ ์์ฒญ๋น 1~2์ด, ๊ณต์ ๋ฌด๋ฃ CPU์์๋ ๋ ๋๋ฆผ.
RM-DETECT๋ ์ฐ๊ตฌ์ฉ ํ๋กํ ํ์ ์ด๋ฉฐ ํ๋ฅ ์ ์ถ์ ์ ๋๋ค. ํ๋ฌธ์ ๋ถ์ ํ์ยท์ฑ์ฉ ๋ฑ ์ค๋ํ ๊ฒฐ์ ์ ๋จ๋ ๊ทผ๊ฑฐ๋ก ์ฌ์ฉํ์ง ๋ง๊ณ , ์ฌ๋ฌ ์ ํธ ์ค ํ๋๋ก๋ง ํ์ฉํ์ธ์.
