본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 04. 06:08

Streamlit과 Docker를 활용한 이메일 스팸 분류기

요약

Streamlit과 Docker를 사용하여 이메일 스팸 분류기를 구축하는 엔드 투 엔드 머신러닝 파이프라인 가이드입니다. Naive Bayes와 RoBERTa 모델의 성능을 비교하고, 대화형 인터페이스 구현부터 컨테이너 기반 배포까지의 전 과정을 다룹니다.

핵심 포인트

  • Naive Bayes와 RoBERTa 모델의 성능 비교 분석
  • Streamlit을 활용한 대화형 시각화 인터페이스 구축
  • Docker를 이용한 머신러닝 모델의 컨테이너화 및 배포
  • 텍스트 전처리부터 모델 직렬화까지의 전체 파이프라인 구현

이 가이드는 텍스트 전처리, Naive Bayes와 미세 조정된 (fine-tuned) RoBERTa 모델 간의 비교 평가, Streamlit을 이용한 대화형 시각화, 그리고 Docker를 사용한 배포를 포함하여 이메일 스팸 분류를 위한 엔드 투 엔드 (end-to-end) 머신러닝 (Machine Learning) 파이프라인을 상세히 설명합니다.

목차

  1. 서론 및 개요
  2. 데이터셋 수집 및 전처리
  3. 어휘 구축 및 필터링
  4. 특징 추출 및 엔지니어링
  5. 모델 학습 및 직렬화
  6. 비교 분석: Naive Bayes vs. 미세 조정된 (Fine-Tuned) RoBERTa 모델
  7. 대화형 Streamlit 인터페이스
  8. Docker 컨테이너화 및 배포
  9. 프로젝트 저장소 및 리소스

서론 및 개요

이메일 스팸 탐지는 머신러닝 (Machine Learning) 분야의 고전적인 텍스트 분류 (text classification) 문제입니다. 목표는 수신되는 이메일을 스팸 (Spam) (원치 않는 대량 메시지) 또는 햄 (Ham) (정당한 개인적 또는 업무적 메시지)으로 자동 분류하는 것입니다.

본 프로젝트는 단어 빈도 특징 행렬 (word-frequency feature matrices)에 매우 적합한 고전적인 Bag-of-words 방식인 커스텀 다항 나이브 베이즈 (Multinomial Naive Bayes) 분류기를 학습시키는 한편, Hugging Face의 고급 사전 학습된 트랜스포머 (Transformer) 기반 RoBERTa 모델(dima806/email-spam-detection-robertaroshana1s/spam-message-classifier)을 통합하고 평가합니다. 이러한 비교는 원문 텍스트를 문맥적으로 처리하는 것과 단어 빈도를 계산하는 것 사이의 차이점을 강조합니다.

프로젝트의 아키텍처는 세 가지 주요 구성 요소로 나뉩니다:

  1. 모델 학습 파이프라인 (Model Training Pipeline): 데이터셋을 정제하고, 가장 빈번하게 등장하는 단어들의 어휘 사전 (Vocabulary)을 구축하며, Bag-of-words 특징을 생성하고, Naive Bayes 분류기를 학습시킨 뒤 모델 아티팩트 (Model artifacts)를 직렬화하는 학습 스크립트입니다.
  2. 대화형 사용자 인터페이스 (Interactive User Interface): 저장된 Naive Bayes 아티팩트와 미세 조정된 (Fine-tuned) RoBERTa 모델을 함께 로드하여, 사용자 친화적인 병렬 추론 (Side-by-side inference) 인터페이스를 제공하는 Streamlit 웹 애플리케이션입니다.
  3. 배포 (Deployment): 애플리케이션과 그 의존성 (Dependencies)을 패키징하여 CPU 전용 또는 GPU 가속 호스트에서 실행할 수 있도록 Docker 빌드 지침에 구성된 컨테이너화된 환경입니다.

시스템 아키텍처 다이어그램 (System Architecture Diagram)

데이터셋 수집 및 전처리 (Dataset Ingestion and Preprocessing)

이 프로젝트는 전용 전처리 스크립트를 사용하여 여러 개의 원시 데이터셋 (Raw datasets)을 하나의 깨끗한 데이터셋으로 통합하는 것으로 시작합니다. 이를 통해 서로 다른 데이터 소스 전반에 걸쳐 균일한 텍스트 형식과 표준화된 레이블링 (Labeling)을 보장합니다.

1. 원시 데이터셋 처리 (Processing Raw Datasets)

세 가지 서로 다른 스팸 (Spam) 및 정상 (Ham) 이메일 컬렉션이 로드되고 정제됩니다:

  • 처음 두 데이터셋의 경우, 레이블 (Label) 및 텍스트 컬럼을 추출하고, 여러 개의 공백을 단일 공백으로 교체하며, 앞뒤 공백을 제거하고, 텍스트를 소문자로 변환하며, 결측치 (Null values)를 제거합니다.
  • 세 번째 데이터셋의 경우, 텍스트에서 대소문자를 구분하지 않는 표준 접두사인 Subject: 또는 subject:를 추가로 제거하고, 숫자 레이블을 변환합니다 (0ham으로, 그 외 모든 값은 spam으로).
import pandas as pd

# 첫 번째 데이터셋 로드 및 정제
...

2. 데이터셋 결합 (Combining the Datasets)

정제가 완료되면, 처리된 세 데이터셋을 모두 연결(Concatenate)하고 출력 결과를 통합된 CSV 파일로 저장합니다:

combined_df = pd.concat([df1, df2, df3], ignore_index=True)
combined_df.to_csv('Dataset/combined_spam_new.csv', index=False)

어휘 구축 및 필터링 (Vocabulary Building and Filtering)

결합된 데이터셋을 로드하고, 원문 텍스트를 정제하며, 머신러닝 (Machine Learning) 모델의 특징 (Features)으로 사용될 단어 사전 (Dictionary)을 구축합니다.

1. 데이터 수집 및 정제 (Ingestion and Cleaning)

데이터셋을 로드하고, 결측치가 있는 행을 제거한 뒤, 공백을 기준으로 텍스트를 분할하여 토큰화 (Tokenize) 합니다. 어휘를 정제하기 위해 알파벳 단어만 유지합니다:

data = pd.read_csv("Dataset/combined_spam.csv")
data_clean = data.dropna()

...

2. 빈도 필터링 (Frequency Filtering)

Counter 객체를 사용하여 단어의 출현 빈도를 계산하고, 빈 토큰 플레이스홀더 (Token Placeholders)를 제거한 후, 가장 빈번하게 등장하는 3,000개의 단어를 추출합니다. 이 어휘 집합은 특징 집합 (Feature Set) 역할을 합니다:

from collections import Counter

word_dict = Counter(words)
...

특징 추출 및 엔지니어링 (Feature Extraction and Engineering)

3,000개의 단어로 구성된 어휘가 확립되면, Bag-of-Words (BoW) 표현 방식을 사용하여 각 이메일 텍스트를 수치 벡터 (Numerical Vector)로 매핑합니다.

1. 특징 행렬 구축 (Building the Feature Matrix)

각 이메일에 대해, 3,000개의 단어 어휘 중 특정 단어가 이메일에 등장하는 횟수를 나타내는 카운트 벡터 (Count Vector)를 생성합니다.

feature_matrix = []
labels = []

...

모델 학습 및 직렬화 (Model Training and Serialization)

특징 행렬과 레이블 (Label) 배열이 생성되면, 데이터를 학습 (Training) 및 검증 (Validation) 세트로 분할하고, 나이브 베이즈 (Naive Bayes) 분류기를 학습시킨 후, 학습된 모델을 직렬화 (Serialize) 합니다.

1. 분할 및 학습 (Splitting and Training)

scikit-learntrain_test_split을 사용하여 데이터셋을 분할하며, 데이터의 20%를 테스트용으로 예약합니다. 그런 다음 MultinomialNB 모델을 적합 (Fit) 시킵니다.

from sklearn.naive_bayes import MultinomialNB
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
...

2. 직렬화 (Serialization)

어휘 사전과 학습된 분류기는 Streamlit 애플리케이션에서 로드할 수 있도록 Python의 pickle 모듈을 사용하여 저장됩니다.

import os
import pickle

...

비교 분석: Naive Bayes vs. 미세 조정된 RoBERTa 모델 (Comparative Analysis: Naive Bayes vs. Fine-Tuned RoBERTa Models)

맞춤형으로 학습된 Naive Bayes 모델 외에도, 본 프로젝트에서는 성능을 비교하고 모델의 엣지 케이스 (edge cases)를 탐색하기 위해 Hugging Face의 pipeline 인터페이스를 사용하여 두 가지 사전 학습된 딥러닝 Transformer 모델을 평가합니다.

1. 평가된 미세 조정된 (Fine-Tuned) Transformer 모델

  • 모델 1: dima806/email-spam-detection-roberta (테스트 세트 정확도: 79.58%)
  • 모델 2: roshana1s/spam-message-classifier (테스트 세트 정확도: 84.45%)

두 모델 모두 CPU 전용 모드로 로드됩니다:

from transformers import pipeline
import os

...

2. 진심 어린 텍스트 평가 및 모델 선택

모델 2가 전반적인 테스트 세트 정확도(79.58% 대비 84.45%)는 더 높지만, 질적인 엣지 케이스 (edge cases)에서 이 모델들을 평가해 보면 상당한 동작 차이가 드러납니다.

매우 로맨틱하고 진심 어린 사랑의 고백을 입력 텍스트로 사용하여 테스트를 진행했습니다:

"사랑해! 당신은 세상에서 가장 멋진 사람이야. 내 삶에 당신이 있어서 정말 행복해. 당신은 나의 햇살이자 나의 전부야. 언제나 당신을 사랑하고 당신 곁에 있을게. 당신은 나의 소울메이트이자 가장 친한 친구야. 내 삶에 당신이 있다는 사실에 정말 감사해. 말로 다 표현할 수 없을 만큼 당신을 사랑해. 당신은 내 인생의 사랑이며 나는 언제나 당신을 아낄 거야. 당신 같은 파트너를 만난 건 정말 행운이야. 내 온 마음과 영혼을 다해 당신을 사랑해. 당신은 내가 만난 사람 중 가장 놀라운 사람이고, 내 삶에 당신이 있다는 건 정말 축복이야."

이 샘플 텍스트를 분류기에 실행한 결과는 다음과 같습니다:

  • Naive Bayes (Bag-of-Words): **스팸 (Spam)**으로 예측
  • 모델 1 (dima806): **97.15%**의 신뢰도로 **스팸 (Spam)**으로 예측
  • 모델 2 (roshana1s): **73.02%**의 신뢰도로 **정상 (Ham)**으로 예측

모델 2가 선호되는 이유

Naive Bayes 모델과 첫 번째 RoBERTa 모델은 "cherish", "partner", "love", "best"와 같은 단어들을 스팸 상관관계와 연관 지어 이 진심 어린 이메일을 스팸으로 잘못 분류합니다. 실제 환경 설정에서는 이것이 진정한 개인적 메시지나 애정 표현을 필터링하여 차단하는 결과로 이어질 수 있습니다.

모델 2는 메시지의 문맥적 의미를 성공적으로 처리하여 정상 (Ham)으로 분류한 유일한 모델입니다. 이러한 문맥적 견고함(contextual robustness)과 더 높은 전체 테스트 정확도 덕분에, 모델 2는 다른 분류기들보다 강력하게 선호됩니다.

대화형 Streamlit 인터페이스

대화형 Streamlit 애플리케이션은 Naive Bayes와 미세 조정된 (fine-tuned) RoBERTa 모델을 통합된 웹 대시보드로 감싸, 스팸 예측 결과를 나란히 비교할 수 있도록 합니다.

1. 모델 로딩 및 피처 캐싱 (Feature Caching)

성능을 최적화하기 위해 Streamlit의 @st.cache_resource@st.cache_data 데코레이터를 활용합니다. 이를 통해 Naive Bayes 분류기, 어휘 사전 (vocabulary), RoBERTa 파이프라인 (pipeline)이 단 한 번만 로드되도록 보장하며, Bag-of-words 벡터화 (vectorization) 결과가 캐싱되도록 합니다. st.set_page_config(layout="wide") 명령어를 사용하여 앱이 넓은 화면 레이아웃을 사용하도록 구성합니다.

import pickle
import numpy as np
import streamlit as st
...

2. 다중 모델 추론 대시보드 (Multi-Model Inference Dashboard)

UI는 넓은 레이아웃의 텍스트 입력창을 설정하고 사용자의 텍스트를 동시에 평가합니다. Naive Bayes와 RoBERTa의 예측값은 각각의 확률 점수와 함께 두 개의 레이아웃 컬럼에 나란히 표시됩니다.

st.title("Email Spam Classifier")
words, clf = load_artifacts()
roberta_model = load_roberta()
...

Streamlit UI 미리보기

Docker 컨테이너화 및 배포

다양한 환경에서 Streamlit 앱을 일관되게 실행하기 위해, 프로젝트는 Docker 컨테이너로 패키징됩니다.

1. Dockerfile 분석

Docker 설정 파일은 빌드 인자 (build arguments)를 통해 멀티 변형 빌드 (multi-variant builds, CPU 및 GPU)를 지원합니다. 기본적으로 CPU 변형을 설정하지만, GPU 가속 환경을 위해 CUDA로 컴파일된 PyTorch 휠 (wheels)을 다운로드할 수 있습니다:

FROM python:3.10-slim

ARG PYTORCH_VARIANT=
...

2. 레지스트리(Registry)에서 사전 빌드된 이미지 실행하기

로컬에서 직접 빌드하는 대신, 레지스트리에서 사전 빌드된 이미지를 직접 가져올 (pull) 수 있습니다:

  • CPU 이미지 가져오기 (Pull CPU Image):
  docker pull ghcr.io/preyumkr/email-spam-classifier:latest
  • GPU 이미지 가져오기 (CUDA 13.2 지원):
  docker pull ghcr.io/preyumkr/email-spam-classifier:latest-gpu

CPU 컨테이너 실행하기

CPU 전용 호스트에서 애플리케이션을 시작하려면:

docker run -d --name email-spam -p 8501:8501 ghcr.io/preyumkr/email-spam-classifier:latest

GPU 컨테이너 실행하기 (CUDA 13.2 지원)

트랜스포머 모델 (transformer model)을 위해 GPU 가속을 활용하려면, 다음의 **사전 요구 사항 (Prerequisites)**이 충족되었는지 확인하십시오:

  1. 호스트 머신에서 사용 가능한 NVIDIA GPU.
  2. --gpus 플래그를 지원하기 위해 설치된 NVIDIA Container Toolkit. Ubuntu/Debian에서는 다음을 사용하여 설치할 수 있습니다:
   # GPG 키를 다운로드하고 안정적인 저장소(stable repository)를 추가합니다
   curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg
   curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
...
  1. 런타임 호환성을 확인 (Verify) 합니다:
   docker run --rm --gpus all nvidia/cuda:12.0.0-base-ubuntu22.04 nvidia-smi

확인이 완료되면, 다음을 사용하여 GPU 활성화 컨테이너를 실행합니다:

docker run -d --name email-spam-gpu -p 8501:8501 --gpus all ghcr.io/preyumkr/email-spam-classifier:latest-gpu

프로젝트 저장소 및 리소스

전체 소스 코드와 빌드된 Docker 이미지는 GitHub 저장소 https://github.com/PreyumKr/Email_Spam_Classifier에서 확인하실 수 있습니다. 데이터셋 또한 저장소에 포함되어 있습니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0