|
|
--- |
|
|
license: mit |
|
|
language: |
|
|
- ko |
|
|
base_model: |
|
|
- beomi/KcELECTRA-base |
|
|
pipeline_tag: text-classification |
|
|
tags: |
|
|
- digitalhumanities |
|
|
- emotion |
|
|
- classification |
|
|
--- |
|
|
|
|
|
**KPoEM (Korean Poetry Emotion Mapping) 모델**은 한국 근대시에 특화된 KcELECTRA 기반의 감정 분류 모델로, [KcELECTRA-base](https://huggingface.co/beomi/KcELECTRA-base/tree/main)에 [KOTE dataset](https://huggingface.co/datasets/searle-j/kote)을 파인튜닝한 모델을, 다시 KPoEM dataset으로 파인튜닝하여 구현한 모델입니다. |
|
|
|
|
|
# Contributors |
|
|
LIM, I., Ji, H., & Kim, B. |
|
|
|
|
|
- **Prerprint Paper**: [Decoding the Poetic Language of Emotion in Korean Modern Poetry: Insights from a Human-Labeled Dataset and AI Modeling](https://doi.org/10.48550/arXiv.2509.03932) |
|
|
|
|
|
# Resources |
|
|
모델 학습에 사용한 자원들은 아래 링크에서 확인하실 수 있습니다. |
|
|
- 데이터세트: Zenodo, [KPoEM dataset](https://zenodo.org/records/15572285) Hugging Face, [KPoEM dataset](https://huggingface.co/datasets/AKS-DHLAB/KPoEM) |
|
|
- 파인튜닝 소스코드: GitHub, [AKS-DHLAB/KPoEM](https://github.com/AKS-DHLAB/KPoEM) |
|
|
|
|
|
# Model |
|
|
KPoEM 모델의 활용은 다음의 코드를 참고해 주시기를 바랍니다. |
|
|
|
|
|
``` |
|
|
# 필요 라이브러리 설치 (최초 1회만 실행) |
|
|
!pip install -q transformers torch huggingface_hub |
|
|
|
|
|
# 라이브러리 임포트 |
|
|
import torch |
|
|
import torch.nn as nn |
|
|
from transformers import AutoModel, AutoTokenizer |
|
|
from huggingface_hub import hf_hub_download |
|
|
|
|
|
|
|
|
# 기초 세팅 |
|
|
REPO_ID = "AKS-DHLAB/KPoEM" |
|
|
DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu") |
|
|
|
|
|
# KPoEM_Classifier 클래스 |
|
|
class KPoEM_Classifier(nn.Module): |
|
|
|
|
|
# 클래스 생성 시 모든 초기화(모델/토크나이저/가중치 로드) 수행 |
|
|
def __init__(self, repo_id, device): |
|
|
self.labels = [ |
|
|
'불평/불만', '환영/호의', '감동/감탄', '지긋지긋', '고마움', '슬픔', '화남/분노', '존경', |
|
|
'기대감', '우쭐댐/무시함', '안타까움/실망', '비장함', '의심/불신', '뿌듯함', '편안/쾌적', |
|
|
'신기함/관심', '아껴주는', '부끄러움', '공포/무서움', '절망', '한심함', '역겨움/징그러움', |
|
|
'짜증', '어이없음', '없음', '패배/자기혐오', '귀찮음', '힘듦/지침', '즐거움/신남', '깨달음', |
|
|
'죄책감', '증오/혐오', '흐뭇함(귀여움/예쁨)', '당황/난처', '경악', '부담/안_내킴', '서러움', |
|
|
'재미없음', '불쌍함/연민', '놀람', '행복', '불안/걱정', '기쁨', '안심/신뢰' |
|
|
] |
|
|
num_labels = len(self.labels) |
|
|
|
|
|
super().__init__() |
|
|
self.device = device |
|
|
self.tokenizer = AutoTokenizer.from_pretrained(repo_id) |
|
|
self.electra = AutoModel.from_pretrained(repo_id) |
|
|
self.classifier = nn.Sequential( |
|
|
nn.Dropout(p=0.1), |
|
|
nn.Linear(self.electra.config.hidden_size, num_labels) |
|
|
) |
|
|
|
|
|
weights_path = hf_hub_download(repo_id=repo_id, filename="classifier_state.bin") |
|
|
self.classifier.load_state_dict(torch.load(weights_path, map_location=self.device)) |
|
|
self.to(self.device) |
|
|
self.eval() |
|
|
|
|
|
# 텍스트를 입력받아 최종 logits 반환 |
|
|
def forward(self, text: str): |
|
|
encoding = self.tokenizer( |
|
|
text, |
|
|
add_special_tokens=True, |
|
|
max_length=512, |
|
|
padding="max_length", |
|
|
truncation=True, |
|
|
return_tensors='pt', |
|
|
).to(self.device) |
|
|
|
|
|
with torch.no_grad(): |
|
|
outputs = self.electra( |
|
|
input_ids=encoding["input_ids"], |
|
|
attention_mask=encoding["attention_mask"], |
|
|
token_type_ids=encoding["token_type_ids"] |
|
|
) |
|
|
|
|
|
pooled_output = outputs.last_hidden_state[:, 0, :] |
|
|
logits = self.classifier(pooled_output) |
|
|
return logits |
|
|
|
|
|
# 텍스트 분석 결과 반환 |
|
|
def analyze(self, text: str, threshold=0): |
|
|
logits = self.forward(text) |
|
|
probabilities = torch.sigmoid(logits.squeeze()) |
|
|
predictions = (probabilities > threshold).int() |
|
|
|
|
|
detected_emotions = [] |
|
|
for i, label_id in enumerate(predictions): |
|
|
if label_id == 1: |
|
|
emotion = self.labels[i] |
|
|
probability = probabilities[i].item() |
|
|
detected_emotions.append((emotion, probability)) |
|
|
|
|
|
# 확률값을 기준으로 내림차순 정렬 |
|
|
detected_emotions.sort(key=lambda x: x[1], reverse=True) |
|
|
return detected_emotions |
|
|
|
|
|
|
|
|
# KPoEM 모델 로드 |
|
|
print(f"... '{DEVICE}' 환경에서 '{REPO_ID}' 모델을 로드하고 있습니다 ...") |
|
|
kpoem_model = KPoEM_Classifier(repo_id=REPO_ID, device=DEVICE) |
|
|
print("KPoEM 모델을 성공적으로 로드하였습니다.") |
|
|
``` |
|
|
|
|
|
상기 코드의 대화형 환경에서의 실행 결과는 다음과 같습니다. |
|
|
|
|
|
``` |
|
|
... 'cpu' 환경에서 'AKS-DHLAB/KPoEM' 모델을 로드하고 있습니다 ... |
|
|
KPoEM 모델을 성공적으로 로드하였습니다. |
|
|
``` |
|
|
|
|
|
다음은 로드한 모델을 실행하는 예시 코드입니다. |
|
|
|
|
|
``` |
|
|
# 예시1 |
|
|
example1 = "나의 생은 미친듯이 사랑을 찾아 헤매었으나" |
|
|
result1 = kpoem_model.analyze(example1) |
|
|
result1 |
|
|
``` |
|
|
|
|
|
다음은 예시 코드를 실행한 결과입니다. |
|
|
|
|
|
``` |
|
|
[('슬픔', 0.9469444751739502), |
|
|
('서러움', 0.937518298625946), |
|
|
('안타까움/실망', 0.9196950793266296), |
|
|
('불안/걱정', 0.7706277966499329), |
|
|
('힘듦/지침', 0.7137402892112732), |
|
|
('깨달음', 0.6845079660415649), |
|
|
('비장함', 0.6476397514343262), |
|
|
('불쌍함/연민', 0.6128569841384888), |
|
|
('부담/안_내킴', 0.5575793981552124), |
|
|
('기대감', 0.4775768220424652), |
|
|
('당황/난처', 0.4501192569732666), |
|
|
('패배/자기혐오', 0.4364185035228729), |
|
|
('절망', 0.4248308539390564), |
|
|
('불평/불만', 0.3876761496067047), |
|
|
('아껴주는', 0.3849319517612457), |
|
|
('감동/감탄', 0.31014394760131836), |
|
|
('신기함/관심', 0.2456621527671814), |
|
|
('지긋지긋', 0.20546969771385193), |
|
|
('놀람', 0.18827176094055176), |
|
|
('한심함', 0.1782034933567047), |
|
|
('재미없음', 0.1595412939786911), |
|
|
('죄책감', 0.15579494833946228), |
|
|
('부끄러움', 0.13476116955280304), |
|
|
('환영/호의', 0.13304632902145386), |
|
|
('의심/불신', 0.12566028535366058), |
|
|
('존경', 0.11981170624494553), |
|
|
('기쁨', 0.11800216883420944), |
|
|
('행복', 0.08473784476518631), |
|
|
('뿌듯함', 0.07957974821329117), |
|
|
('어이없음', 0.07822196185588837), |
|
|
('없음', 0.07102902233600616), |
|
|
('경악', 0.07033637911081314), |
|
|
('짜증', 0.06384478509426117), |
|
|
('화남/분노', 0.06323148310184479), |
|
|
('흐뭇함(귀여움/예쁨)', 0.06262417882680893), |
|
|
('즐거움/신남', 0.06152398884296417), |
|
|
('고마움', 0.056765031069517136), |
|
|
('우쭐댐/무시함', 0.05257101356983185), |
|
|
('공포/무서움', 0.05099816992878914), |
|
|
('귀찮음', 0.043061513453722), |
|
|
('편안/쾌적', 0.042331695556640625), |
|
|
('안심/신뢰', 0.04192497953772545), |
|
|
('증오/혐오', 0.03919696435332298), |
|
|
('역겨움/징그러움', 0.013086128979921341)] |
|
|
``` |
|
|
|
|
|
다음과 같이 임계값(threshold)을 임의로 줄 수도 있습니다. |
|
|
|
|
|
``` |
|
|
# 예시2 |
|
|
example2 = ''' |
|
|
나의 생은 미친듯이 사랑을 찾아 헤매었으나 |
|
|
단 한번도 스스로를 사랑하지 않았노라 |
|
|
''' |
|
|
result2 = kpoem_model.analyze(example2, threshold=0.3) # 임계값 0.3으로 설정 |
|
|
result2 |
|
|
``` |
|
|
|
|
|
위와 같이 threshold 인자를 줄 경우, 확률 값이 0.3 이상인 감정만 반환됩니다. |
|
|
|
|
|
``` |
|
|
[('슬픔', 0.9411415457725525), |
|
|
('서러움', 0.9244144558906555), |
|
|
('안타까움/실망', 0.9239906668663025), |
|
|
('깨달음', 0.7170049548149109), |
|
|
('불안/걱정', 0.6184237599372864), |
|
|
('힘듦/지침', 0.6009577512741089), |
|
|
('불쌍함/연민', 0.5903952121734619), |
|
|
('패배/자기혐오', 0.5515390038490295), |
|
|
('비장함', 0.5166702270507812), |
|
|
('당황/난처', 0.48103633522987366), |
|
|
('부담/안_내킴', 0.45452776551246643), |
|
|
('절망', 0.4479917585849762), |
|
|
('불평/불만', 0.388106107711792), |
|
|
('한심함', 0.34834057092666626), |
|
|
('아껴주는', 0.3062174916267395), |
|
|
('부끄러움', 0.3003148138523102)] |
|
|
``` |
|
|
|
|
|
# References |
|
|
- [KcELECTRA](https://github.com/Beomi/KcELECTRA) |
|
|
- [KOTE](https://github.com/searle-j/KOTE) |
|
|
- [KOTE Dataset](https://huggingface.co/datasets/searle-j/kote) |