Downloads · 30 days
23
22% of all-time downloads
MelissaJ/koelectra-emotion-7-emotion-base-onnx
koelectra-emotion-7-emotion-base-onnx is a text classification model from MelissaJ. Use it when you need a label for a piece of text. It is set up for onnx. The card lists the license as apache-2.0.
한국어 문장의 감정을 분류하는 KoELECTRA-base-v3 파인튜닝 모델의 ONNX 변환본입니다. 문장 1개를 입력하면 7개 클래스 — 감정 6종(기쁨, 분노, 상처, 불안, 당황, 슬픔) + 중립(감정 없음) — 의 확률을 출력합니다.
Downloads · 30 days
23
22% of all-time downloads
All-time downloads
106
Public
Repo size
904 MB
Likes
0
Public
Click a slice to open those files.
.onnx452 MB · 100%
From the Hugging Face model README
한국어 문장의 감정을 분류하는 KoELECTRA-base-v3 파인튜닝 모델의 ONNX 변환본입니다. 문장 1개를 입력하면 7개 클래스 — 감정 6종(기쁨, 분노, 상처, 불안, 당황, 슬픔) + 중립(감정 없음) — 의 확률을 출력합니다.
PyTorch·transformers·CUDA가 전혀 필요 없습니다. 런타임 의존성은 onnxruntime + tokenizers + numpy 3개뿐이며, CPU에서 문장 1개당 수십 ms로 동작해 GPU 없는 배포 환경에 적합합니다.
torch.onnx.export)| 파일 | 설명 |
|---|---|
model.onnx | 모델 본체 (fp32, 약 452MB) |
tokenizer.json | HuggingFace tokenizers 포맷 토크나이저 |
config.json | 라벨 매핑(id2label) 포함 — 별도 라벨 파일 불필요 |
pip install onnxruntime tokenizers numpy huggingface_hub
import json
from pathlib import Path
import numpy as np
import onnxruntime as ort
from huggingface_hub import snapshot_download
from tokenizers import Tokenizer
model_dir = Path(snapshot_download("MelissaJ/koelectra-emotion-7-emotion-base-onnx"))
tokenizer = Tokenizer.from_file(str(model_dir / "tokenizer.json"))
tokenizer.enable_truncation(128)
session = ort.InferenceSession(
str(model_dir / "model.onnx"), providers=["CPUExecutionProvider"]
)
config = json.loads((model_dir / "config.json").read_text(encoding="utf-8"))
id2label = {int(i): label for i, label in config["id2label"].items()}
def classify_emotion(text: str) -> dict[str, float]:
enc = tokenizer.encode(text)
feeds = {
"input_ids": np.array([enc.ids], dtype=np.int64),
"attention_mask": np.array([enc.attention_mask], dtype=np.int64),
"token_type_ids": np.array([enc.type_ids], dtype=np.int64),
}
logits = session.run(None, feeds)[0][0]
exp = np.exp(logits - logits.max())
probs = exp / exp.sum()
return dict(
sorted(
((id2label[i], float(p)) for i, p in enumerate(probs)),
key=lambda x: -x[1],
)
)
print(classify_emotion("오늘 드디어 합격 소식을 들었어!"))
# {'기쁨': 0.998, ...}
"오늘 드디어 합격 소식을 들었어!" → 기쁨 0.998
"밤마다 미래가 걱정돼서 잠이 안 와." → 불안 0.489 (2위 상처 0.300)
"오늘 회의는 3시에 시작합니다." → 중립 1.000
"점심 뭐 먹을까?" → 중립 1.000
CPU만으로 충분히 빠르지만, 필요하면 onnxruntime-gpu 설치 후 providers만 바꾸면 됩니다:
session = ort.InferenceSession(
str(model_dir / "model.onnx"),
providers=["CUDAExecutionProvider", "CPUExecutionProvider"],
)
| 클래스 | 소스 | train / val |
|---|---|---|
| 감정 6종 | AI Hub 감성대화말뭉치 (사람문장1~3을 독립 샘플로 전개) | 144,696 / 17,910 |
| 중립 | KLUE-YNAT 뉴스 제목 | 12,000 / 1,500 |
| 중립 | 송영숙 챗봇 데이터 일상(label 0) 질문 | 4,734 / 525 |
| 중립 | KorNLI 전제문 (train: MultiNLI, val: XNLI dev+test) | 8,000 / 1,000 |
총 train 169,430 / val 20,935 문장. 클래스 불균형(기쁨이 적음)은 weighted cross-entropy로 보정했습니다.
대화 스타일 증강 (v2, 2026-08): train/val 각 50%에 호명("○○님!", "○○아,"), 구어 감탄("아이고, 진짜!", "어휴," 등), 말줄임("...")을 라벨 불변으로 전 클래스에 균일 주입했습니다. v1은 중립 소스가 전부 뉴스·챗봇체라 "호명·구어 감탄 = 중립"이라는 도메인 지름길을 학습했고, 캐릭터 대화체 감정 발화("멜리사님! 정말 화가 난다!")가 중립 확률 ~1.0으로 포화되는 문제가 실측됐습니다. 균일 주입으로 이 지름길을 차단했습니다.
ONNX 변환은 무손실에 가깝습니다(로짓 차이 1e-3 이내, v2 실측 최대 4e-5). 아래는 원본 모델 기준 성능이며, v2의 val은 증강 분포라 v1 수치(acc 0.6790 / f1_macro 0.6744)와 직접 비교할 수 없습니다.
| 지표 | 값 |
|---|---|
| accuracy | 0.6745 |
| f1_macro | 0.6699 |
| f1_weighted | 0.6757 |
| 클래스 | precision | recall | f1 |
|---|---|---|---|
| 기쁨 | 0.8975 | 0.8610 | 0.8789 |
| 분노 | 0.6380 | 0.6045 | 0.6208 |
| 상처 | 0.5208 | 0.4969 | 0.5086 |
| 불안 | 0.5749 | 0.5952 | 0.5849 |
| 당황 | 0.5271 | 0.5979 | 0.5603 |
| 슬픔 | 0.5484 | 0.5433 | 0.5458 |
| 중립 | 0.9930 | 0.9864 | 0.9897 |
호명·감탄 회귀 프로브(v1에서 전부 중립 ~1.0 포화)가 v2에서 올바른 감정으로 복귀: "멜리사님! 정말 화가 난다!" → 분노 0.79, "...아이고, 진짜! ○○님는 나한테 맨날 일만 시키지!" → 분노 0.98. 호명 섞인 중립("○○님, 오늘 회의는 3시에 시작합니다")은 중립 유지.