완벽한 스미싱 분류 모델을 향해서 (1)

2025. 5. 27. 00:06·AI
728x90

스미싱 분류 모델을 개발해야지! 라고 생각했던 처음의 포부와는 달리, 파인튜닝을 하는 편이 리소스나 시간 면에서 좋을 것 같다는 생각이 들었다. BERT 모델을 직접 파인튜닝하는 것보다 HuggingFace에서 제공하는 라이브러리를 이용하면 더 쉽게 파인튜닝할 수 있다!

허깅페이스는 다양한 트랜스포머 모델과 학습 스크립트를 제공하는 모듈로, 다양한 트랜스포머 모델을 손쉽게 이용할 수 있기 때문.

트랜스포머(Transformer)란?

CNN, RNN과 같이 인공지능 분야에서 많이 사용되는 모델 중 하나가 트랜스포머라고 할 수 있다. 트랜스포머 모델은 문장 속 단어들과 같은 순차 데이터 내의 관계를 한꺼번에 파악해서 문장의 맥락과 의미를 더 잘 이해할 수 있도록 학습하는 신경망이다.

 

예전에는 문장을 처리할 때 순서대로 읽는 RNN, LSTM 같은 모델을 사용했는데, 문장이 길어지면 앞뒤 단어의 관계를 기억하기 어렵다는 문제가 있었다. 이를 해결한게 바로 트랜스포머 모델이다. 트랜스포머 모델의 핵심은 어텐션(Attention)에 있는데, 이 어텐션은 문장 안의 단어들 중에서 현재 처리 중인 단어와 관련 있는 단어에 더 집중(가중치 부여)하는 기술을 말한다.

예) "철수가 사과를 먹었다."

이때, 먹었다는 단어를 처리할 떄 가장 관련 있는 단어는 사과다. 먹었다와 철수도 관계는 있지만, 먹었다와 사과는 더 직접적인 의미 관계가 있다. 어텐션은 모든 단어의 "관계"를 동시에 수치로 계산해서 모델이 중요한 단어에 더 집중할 수 있게 도와준다.

 

문장이 길~어질수록 중요한 단어와 멀리 떨어져있을 확률이 높다.

예) 은우는 이틀 전부터 기획안 마감, 자료 조사, 회의 준비, 발표 리허설, 그리고 팀원들과의 피드백 조율까지 정신없는 일정으로 하루하루를 보내는 와중에도 단 한 번도 점심을 거르지 않고 먹은 유일한 음식은 바로 세 번째 날 아침 일찍 사 둔 사과였다

전통적인 모델을 사용하면 먹었다가 무엇을 먹었는지 이해하기 위해 끝까지 다 기억해야한다. 반면, 어텐션은 문장 전체를 동시에 바라보면서 먹었다와 사과가 중요하게 연결되어있음을 찾아낼 수 있다.

데이터 수집 및 전처리

일단, 데이터는 한국인터넷진흥원에서 제공받은 2025년 3월 스미싱 데이터를 전처리한 스미싱데이터(label:1)와

AI-hub의 일상 구어 말뭉치 데이터를 전처리한 정상데이터(label:0)를 활용해 학습시킬 예정이다.

다만 정상 데이터의 양이 더 많기에 스마트치안빅데이터 플랫폼의 스미싱 문자 데이터를 추가로 구매해서 스미싱 데이터를 확보할 예정이다.(약 3만건 정도)

  1. 해당 데이터를 활용해서 BERT 모델을 파인튜닝하고,
  2. 다국어 버전인 'bert-base-multilingual-cased' 토크나이저를 이용한 dataset encoding을 진행한다.
  3. Trainer를 이용한 model fine tuning, fine tuning 한 모델을 이용한 예측을 진행

즉, 스미싱 여부를 이진 분류(문장 분류)로 분류한다.

우선 text와 label 컬럼으로 이뤄진 데이터셋을 로드해 훈련데이터/검증데이터/테스트데이터로 나눴다.

정상 데이터가 약 10배~20배정도 더 많았기 때문에 다수 클래스인 정상 데이터에 대해 언더샘플링을 적용하여, 소수 클래스인 스미싱 데이터와 개수를 맞췄다.

import pandas as pd
from sklearn.model_selection import train_test_split

# 데이터셋을 로드한다.
df = pd.read_csv("../merged_dataset.csv")
# 우선 훈련데이터, 검증데이터, 테스트데이터로 나눠야 함
# 먼저 train / temp 로 나눔 (stratify로 비율 유지)
train_df, temp_df = train_test_split(
    df,
    test_size=0.3,
    stratify=df["label"],
    random_state=42
)

 

전체 데이터의 70%는 훈련(train), 30%는 임시(temp) 데이터로 나누고, stratify=df["label"]를 넣어 클래스(label)의 비율을 유지했다. 

# temp 데이터를 다시 validation / test 로 나눔
val_df, test_df = train_test_split(
    temp_df,
    test_size=0.5,
    stratify=temp_df["label"],
    random_state=42
)

임시로 분리한 temp 데이터를 다시 50%씩 나누어, 모델의 하이퍼파라미터를 조정하기 위한 검증 데이터(validation)와 최종 성능 평가를 위한 테스트 데이터(test)로 각각 15%씩 할당하였다.

# CSV 파일로 저장
train_df.to_csv("train.csv", index=False)
val_df.to_csv("val.csv", index=False)
test_df.to_csv("test.csv", index=False)

이후, 해당 데이터들을 분리해 CSV파일로 저장했다.

스미싱 분류 모델 학습

from transformers import AutoTokenizer, AutoModelForSequenceClassification, Trainer, TrainingArguments
from datasets import Dataset
import pandas as pd
import os
os.environ["WANDB_DISABLED"] = "true"
# 모델과 토크나이저 로드
model_name = "bert-base-multilingual-cased"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForSequenceClassification.from_pretrained(model_name, num_labels=2)

 

모델은, 다국어를 지원하는 BERT모델인 "bert-base-multilingual-cased"모델 사용했다.

 

google-bert/bert-base-multilingual-cased · Hugging Face

BERT multilingual base model (cased) Pretrained model on the top 104 languages with the largest Wikipedia using a masked language modeling (MLM) objective. It was introduced in this paper and first released in this repository. This model is case sensitive:

huggingface.co

from sklearn.metrics import classification_report
import numpy as np

# test.csv 불러오기
test_df = pd.read_csv("test.csv")
test_dataset = Dataset.from_pandas(test_df)

# 토크나이징
def tokenize_fn(example):
    return tokenizer(example["text"], padding="max_length", truncation=True, max_length=128)

tokenized_test = test_dataset.map(tokenize_fn)

# 예측
predictions = trainer.predict(tokenized_test)
y_pred = np.argmax(predictions.predictions, axis=1)
y_true = predictions.label_ids

# 결과 출력
print(classification_report(y_true, y_pred, target_names=["정상", "스미싱"]))

학습시킨 모델에 test.csv 데이터로 테스트한 결과 100%의 예측률을 보였다..

기뻤지만, 100%는 좋지 않은데 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 

 

이후에 다른 데이터들을 테스트하며 문제가 있다는 사실을 깨달았다.

현재 스미싱 데이터에는 대부분 [URL]이 들어있고, 정상 데이터에는 [URL]이 들어있지 않다.

그러다보니 아래와 같은 정상 데이터를 넣었을 때,

[Web발신]
고객님께서 처리하신 업무는 상담사 연결없이 모바일 통해서도 이용하실 수 있습니다. 
[URL]
[{'label': 'LABEL_1', 'score': 0.999981164932251}]

99.9%로 스미싱이라는 결과를 출력하게 된다.

 

언더샘플링을 한게 문제였을까 ? 그래서 일단 팀원들과 함께 정상문자+[URL]인 데이터셋을 만들기로 했다.

메시지함을 뒤져서 배송 및 카드 등등의 정상 데이터를 학습시켜봐야지

 

728x90

'AI' 카테고리의 다른 글

[밑바닥부터 시작하는 딥러닝] ch2. 퍼셉트론  (0) 2026.05.24
완벽한 스미싱 분류 모델을 향해서 (2)  (1) 2025.05.28
[LLM] RAG와 Vector Database  (0) 2025.05.26
[NLP] 1. 텍스트 마이닝 기초  (0) 2025.05.01
[LLM] Streamlit + Ollama를 통해 LLM 기반 챗봇 웹 앱 구현  (0) 2025.04.14
'AI' 카테고리의 다른 글
  • [밑바닥부터 시작하는 딥러닝] ch2. 퍼셉트론
  • 완벽한 스미싱 분류 모델을 향해서 (2)
  • [LLM] RAG와 Vector Database
  • [NLP] 1. 텍스트 마이닝 기초
DROPDEW
DROPDEW
💻 Developer | 기록하지 않으면 존재하지 않는다
  • DROPDEW
    제 2장 1막
    DROPDEW
  • 전체
    오늘
    어제
    • Dev (444)
      • App·Android (1)
      • AI (10)
      • BE (50)
        • HTTP 웹 기본 지식 (8)
        • SpringBoot (23)
        • 스프링부트와 JPA 활용 (0)
        • JAVA (1)
        • PHP (11)
      • FE·Client (23)
        • HTML (1)
        • React (19)
        • Unity (1)
      • Data (28)
        • Bigdata (6)
        • Database (1)
        • Python (0)
        • 빅데이터분석기사 (13)
      • Infra (1)
      • Activity (7)
        • Intern (0)
        • SK AI Dream Camp (0)
        • 구름톤 유니브 4기 (1)
        • 리모트 인턴십 6기 (3)
        • 봉사활동 (0)
        • 부스트캠프 AI Tech 8기 (3)
      • CS (8)
      • 취준 (12)
        • 자격증 (4)
        • 인적성·NCS (6)
        • 코테·필기·면접 후기 (2)
      • 코테 (270)
        • Algorithm (222)
        • SQL (35)
        • 정리 (13)
      • 인사이트 (27)
        • 금융경제뉴스 (7)
        • 금융용어·지식 (2)
        • 북마크 (7)
  • 블로그 메뉴

    • 홈
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    오블완
    티스토리챌린지
    매개변수탐색
    백준
    그래프탐색
    투포인터
    문자열
    누적합
    그리디알고리즘
    구현
    브루트포스 알고리즘
    그래프이론
    이분탐색
    최단경로
    수학
    너비우선탐색
    시뮬레이션
    정렬
    다이나믹프로그래밍
    자료구조
  • 최근 댓글

  • 최근 글

  • 250x250
  • hELLO· Designed By정상우.v4.10.3
DROPDEW
완벽한 스미싱 분류 모델을 향해서 (1)
상단으로

티스토리툴바