[RNN] Vanila RNN을 이용한 SPAM Filter구현

2020. 4. 19. 00:30Artificial Intelligence

https://blog.thomasnet.com/best-practices-spam-filters

 

 

 

지난 [SPAM FILTER] 간단한 스팸 분류기 포스팅에서는 Scikit-learn 라이브러리와 RandomForest Classifier를 사용해서 간단한 스팸 필터(스팸 분류기)를 만들어보았습니다. 이 스팸 필터의 경우 98%에 가까운 정확도를 보여주었지만, 이는 과대적합의 가능성도 있을 뿐더러(포스팅 당시에는 과대적합여부를 따로 판단하지는 않았습니다.) 단어 사이의 문맥이나 연관 관계를 고려하지 않고, 스팸 메일에 속할만한 단어가 많으면 스팸 메일로 판단할 가능성이 높아지는 방식을 택한다는 한계점이 있었습니다. 따라서 RNN(Recurrent Neural Network)을 이용한 이번 포스팅과 LSTM(Long-Short-Term-Memory)를 이용한 다음 포스팅을 통해서 이를 점진적으로 개선해 나가려고 합니다.

 

 

 

데이터는 Kaggle에 있는 SMS Spam 데이터셋을 이용하였습니다. 해당 데이터를 내려받은 다음 pandas dataframe 형식으로 받아줍니다. 데이터는 "Category"와 "Text" 2개의 항목으로 나누어져 있는데, Category는 해당 이메일이 스팸인지 아닌지를, Text는 해당 이메일의 내용이 담겨 있습니다.

 

 

 

 

지난 포스팅에서와 마찬가지로 스팸 메일 데이터 전처리를 해주어야 합니다. 메일에서 URL이나 숫자 등과 같은 데이터는 공통의 의미를 가지는 텍스트로 대체하고, 모든 메일 안에 있는 단어들을 Dictionary안에 집어넣어 index를 매깁니다.

 

 

이렇게 모든 메일안에 있는 단어들이 순서대로 들어가 있는 Dictionary가 완성되면, 메일을 구성하는 단어들을,  Dictionary에서 해당 단어가 속한 번호로 다 바꾸어 줍니다. 예를 들어서 "I love Soccer"라는 문장이 있으면 해당 문장을 구성하는 단어("I", "love", "soccer")를 Dictionary에서 찾아서 해당 단어가 속한 번호 (1, 512, 3221)등으로 변환해 주는 것입니다.

 

 

이렇게 메일을 인덱스의 집합으로 변환하고 나면 One-Hot encoding을 통해 이메일을 사전의 크기와 동일한 크기를 갖는 One-Hot vector로 변환해 줍니다. 예를 들어서 전체 이메일 개수가 5000개이고, 모든 이메일의 단어를 사전으로 만들었을 때, 해당 사전의 크기를 3000개라고 하면, 이메일을 나타내는 벡터는 (5000 * 3000)의 크기를 갖게 되는 것입니다. (일반적으로 사전의 길이는 그 최댓값을 정하는 경우가 많습니다. 이 경우에는 나타나는 빈도가 적은 단어는 사전에서 제외됩니다.)

 

 

지난 포스팅에서는 이 모든 과정을 여러 가지 라이브러리를 import해서 가져다쓰면서 직접 구현했지만, Tensorflow, keras에서 이 모든 과정을 효율적으로 진행할 수 있게 해주는 라이브러리를 이미 구현해놓은 상태이기 때문에 이를 이용해서 전처리 과정을 간단하게 진행하였습니다.

 

 

전처리를 모두 마친 데이터셋은 train_test_split 메서드를 이요해서 20%를 테스트셋 데이터로 사용하고, 80%데이터만 훈련에 사용할 수 있도록 분리해줍니다. 

 

 

 

 

데이터 전처리가 끝난 이후에 Training Set을 이용해서 Vanila RNN을 훈련시킵니다. 구현한 Vanila RNN모델은 다음과 같이 구성됩니다.

 

Word Embedding Layer

Training Set 에서 만들어진 Dictionary의 크기는 8920입니다. 즉 전처리된 email 벡터의 크기가 5572 * 8920이라는 것입니다. 하나의 이메일의 길이가 제한되어 있다는 점을 고려할 때, 8920개중의 대부분은 0으로 표시되어 있을 확률이 굉장히 높습니다. 불필요한 Feature의 수가 많으면 훈련 시간이 길어지고 정확도가 낮아지게 됩니다. 따라서 Word Embedding을 통해 Dataset, 즉 하나의 이메일을 표현하는데 필요한 Feature의 크기를 줄여줍니다.

 

이번 모델에서는 Word_embedding_size = 32로 설정해서 8920개의 Feature를 32개로 축소 시켜서 사용했습니다. 일반적으로 Word embedding column size를 설정할 때에는 Grid탐색이나 Random탐색을 통해 적절한 수를 결정합니다. 

 

 

SimpleRNN Layer

Keras에서 제공하는 SimpleRNN레이어를 사용하였습니다. RNN 의 특성상 LSTM보다는 덜하지만 이전의 데이터가 현재 데이터의 Class를 결정하는데에 영향을 미칩니다. 스팸메일의 특정 단어가 미치는 영향을 고려할 때, 해당 단어 그 자체 뿐만 아니라, 그 단어 이전에 나왔던 단어의 영향도 고려하여 학습을 하게 됩니다. 즉 단어의 문맥을 어느 정도 고려하여 학습하는 것입니다.

 

 

 

Dense Layer

Dense Layer를 통해서 RNN Layer를 통과한 값이 Spam인지(1), 아닌지(0)으로 분류되어 나오게 됩니다. Fully-Connected Layer의 역할을 합니다.

 

 

 

 

 

 

학습 결과 Test셋에서 99%의 정확도를 보이는 것을 알 수 있습니다. 확실히 RandomForest Classifier만을 이용했을때보다 정확도가 올라갔음을 확인할 수 있습니다.

 

 

하지만, 훈련 및 테스트에 사용한 이메일 데이터의 개수가 굉장히 적다는 점(5000여개)등을 고려했을 때, 아직 완벽한 모델이라 불리기에는 한계가 조금 있으며, 다국어 메일 분류, 메일 길이가 아주 긴 경우에 대한 처리, 문맥 학습에 대한 정밀도 측면에서 개선할 부분이 조금 있습니다. 이를 완전히 개선할 수는 없지만, 다음에 살펴볼 LSTM모델에서 이를 조금 더 개선해 볼 수 있을 것입니다.

 

반응형