이번 실습에서는 문장이 하나 이상의 혐오 범주에 속할 수 있는 멀티레이블 분류(Multi-label Classification) 문제를 해결하기 위해 한국어 특화 모델인 KLUE-BERT를 활용했습니다.
데이터셋 개요
- 풀네임: Korean Multi-label Hate Speech Dataset
- 출처: GitHub - adlnlp/K-MHaS
- 데이터 구성:
- kmhas_train.txt: 학습 데이터
- kmhas_valid.txt: 검증 데이터
- kmhas_test.txt: 테스트 데이터
- 형식: 탭(\t)으로 구분된 텍스트 파일 (Document + Label)
1. 멀티레이블 분류의 이해
일반적인 단일 분류(Multi-class)와 달리, 하나의 텍스트가 여러 개의 레이블을 가질 수 있는 구조입니다. 예를 들어, 한 문장이 '성차별'이면서 동시에 '혐오욕설'일 수 있습니다. 이를 처리하기 위해 출력층에서는 Sigmoid 함수를 사용하고, 각 레이블의 포함 여부를 독립적으로 판단합니다.
멀티레이블 구조의 특징
K-MHaS의 가장 큰 특징은 하나의 문장에 여러 레이블이 부여될 수 있다는 점입니다.
- 예시: "저 나이 먹고 특정 종교 믿는 꼴이라니..."
- 레이블 할당: 4 (연령차별), 7 (종교차별) → 모델 입력 시 [0, 0, 0, 0, 1, 0, 0, 1, 0] 형태로 처리됩니다.
2. 데이터 전처리: 레이블 이진화 (Binarization)
데이터셋 내의 레이블(예: '0, 4')을 모델이 학습할 수 있는 수치형 벡터로 변환하는 과정이 필요합니다.
레이블 파싱 및 Binarizing
# 문자열 형태의 레이블을 리스트로 변환
def parse_label(s):
return [int(x) for x in str(s).split(",")]
# MultiLabelBinarizer를 이용한 0과 1의 벡터화
from sklearn.preprocessing import MultiLabelBinarizer
enc = MultiLabelBinarizer()
train_y = [parse_label(s) for s in train['label']]
train_labels = torch.tensor(enc.transform(train_y), dtype=torch.float32)
# 결과 예시: [1, 0, 0, 0, 1, 0, 0, 0, 0] (9개 클래스)
3. 토큰화 및 데이터셋 구축
BERT 모델의 입력 형식에 맞게 데이터를 변환합니다. 실습에서는 효율적인 학습을 위해 전용 함수를 구성했습니다.
데이터 텐서 변환 함수
def data_to_tensor(sentences, labels, tokenizer, max_len=128):
# [CLS], [SEP] 토큰 추가 및 토큰화
# Padding 및 Attention Mask 생성
# ...
return padded_inputs, tensor_labels, attention_masks
# DataLoader 설정 (Batch size 및 병렬 처리 최적화)
train_dataloader = DataLoader(
train_dataset,
batch_size=512,
num_workers=8,
pin_memory=True
)
4. 모델 설정 및 학습 최적화
KLUE-BERT-base 모델을 로드할 때 멀티레이블 설정을 명시적으로 지정합니다.
모델 로드 및 Mixed Precision 적용
A100 등 최신 GPU 환경에서 학습 속도를 높이기 위해 amp.autocast(Mixed Precision)를 사용했습니다.
model = BertForSequenceClassification.from_pretrained(
'klue/bert-base',
num_labels=9,
problem_type='multi_label_classification'
)
# 학습 루프 내 Mixed Precision 적용
from torch import amp
with amp.autocast(device_type="cuda", dtype=torch.bfloat16):
outputs = model(b_input_ids, attention_mask=b_input_mask, labels=b_labels.float())
loss = outputs.loss
5. 성능 평가 지표
멀티레이블 분류에서는 단순 정확도(Accuracy) 외에도 레이블별 성능을 종합하는 지표가 중요합니다.
- F1-Score (Macro/Micro): 클래스 불균형이 있는 데이터셋에서 모델의 성능을 정밀하게 측정합니다.
- Hamming Loss: 전체 레이블 중 모델이 틀린 레이블의 비율을 나타냅니다.
def multi_label_metrics(predictions, labels, threshold=0.5):
probs = torch.sigmoid(torch.Tensor(predictions))
y_pred = (probs >= threshold).numpy().astype(int)
accuracy = accuracy_score(labels, y_pred)
f1_macro = f1_score(labels, y_pred, average='macro', zero_division=0)
# ... 기타 지표 계산
return metrics
6. 실제 문장 추론 (Inference)
학습된 모델을 사용하여 새로운 문장에 대한 혐오 표현을 감지합니다.
def predict_hate_speech(text, threshold=0.5):
model.eval()
inputs = tokenizer(text, return_tensors="pt", padding=True, truncation=True).to(device)
with torch.no_grad():
outputs = model(**inputs)
# Sigmoid를 통해 0~1 사이 확률값 도출
probs = torch.sigmoid(outputs.logits).cpu().numpy()[0]
# threshold 이상인 레이블만 추출
results = [{'label': label_names[i], 'score': prob} for i, prob in enumerate(probs) if prob >= threshold]
return results
테스트 결과 예시:
- 입력: "잼민이들 왜 그렇게 민폐냐?"
- 결과: {'label': '연령차별', 'score': 0.8245}
실습 요약
- 멀티레이블 처리: MultiLabelBinarizer와 BCEWithLogitsLoss의 조합이 핵심입니다.
- 성능 최적화: 대량의 데이터를 처리하기 위해 num_workers, pin_memory, BF16 연산을 활용하여 GPU 효율을 극대화했습니다.
- 한국어 특화: KLUE-BERT를 사용하여 한국어 구어체 및 신조어에 포함된 혐오 뉘앙스를 효과적으로 학습했습니다.
'개념 정리 step2 > 멀티모달(Multi-modal)' 카테고리의 다른 글
| [Deep Learning] 동영상 데이터 분석: 3D CNN과 수화 인식 실습 (0) | 2026.01.29 |
|---|---|
| [Deep Learning] Vision Transformer(ViT) Multi-Branch 구현 실습 (0) | 2026.01.23 |
| [Deep Learning] 트랜스포머(Transformer): NLP 아키텍처 정리 (0) | 2026.01.19 |
| [딥러닝 NLP] NLU에서 트랜스포머 어텐션까지 핵심 개념 정리 (1) | 2026.01.16 |
| [RNN] 시퀀스 데이터와 순환 신경망(RNN) 학습 정리 (1) | 2026.01.15 |
