在Python中如何使用Keras識別垃圾郵件

自1990年代初以來,電子郵件垃圾郵件一直在增長,到2014年,據估計,垃圾郵件約佔傳送的電子郵件的90%。

由於我們所有人都有垃圾郵件填充收件箱的問題,因此在本教程中,我們將在Keras中建立一個模型來區分垃圾郵件和合法電子郵件。

在Python中如何使用Keras識別垃圾郵件

一、安裝和匯入依賴項

我們首先需要安裝一些依賴項:

pip3 install keras sklearn tqdm numpy keras_metrics tensorflow==1。14。0

現在開啟一個互動式shell或bfwstudio並匯入:

import tqdmimport numpy as npimport keras_metrics # for recall and precision metricsfrom keras。preprocessing。sequence import pad_sequencesfrom keras。preprocessing。text import Tokenizerfrom keras。layers import Embedding, LSTM, Dropout, Densefrom keras。models import Sequentialfrom keras。utils import to_categoricalfrom keras。callbacks import ModelCheckpoint, TensorBoardfrom sklearn。model_selection import train_test_splitimport timeimport numpy as npimport pickle

讓我們定義一些超引數:

SEQUENCE_LENGTH = 100 #序列的長度 (每個樣本的單詞數量)

EMBEDDING_SIZE = 100 # 使用100維GloVe嵌入向量

TEST_SIZE = 0。25 #測試比率

BATCH_SIZE = 64 #批次大小

EPOCHS = 20 # 迭代次數#

# 將垃圾郵寄和正常郵件轉成成0和1

label2int = {“ham”: 0, “spam”: 1}

int2label = {0: “ham”, 1: “spam”}

如果您不確定這些引數的含義,請不要擔心,我們稍後將在構建模型時討論它們。

二、載入資料集

我們將使用的資料集是SMS Spam Collection Dataset,下載地址:https://archive。ics。uci。edu/ml/machine-learning-databases/00228/smsspamcollection。zip,下載後解壓並將其放入名為“ data”的資料夾中,讓我們定義載入它的函式:

def load_data():“”“Loads SMS Spam Collection dataset”“”texts, labels = [], []with open(“data/SMSSpamCollection”) as f:for line in f:split = line。split()labels。append(split[0]。strip())texts。append(‘ ’。join(split[1:])。strip())return texts, labels

資料集在一個檔案中,每一行對應一個數據樣本,第一個單詞是標籤,其餘是實際的電子郵件內容,這就是為什麼我們將標籤作為split [0]抓取,並將內容作為split [1: ]。

呼叫函式:

# load the dataX, y = load_data()

三、準備資料集

現在,我們需要一種透過將每個文字轉換為整數序列來向量化文字語料庫的方法,您現在可能想知道為什麼我們需要將文字轉換為整數序列,所以,記住我們要輸入文字進入神經網路,神經網路只能理解數字。更精確地說,是固定長度的整數序列。

但是在執行所有這些操作之前,我們需要透過刪除標點符號,小寫所有字元等來清理該語料庫。幸運的是,Keras具有內建類keras。preprocessing。text。Tokenizer(),該類可以在幾行中完成所有這些工作。程式碼如下:

# Text tokenization# vectorizing text, turning each text into sequence of integerstokenizer = Tokenizer()tokenizer。fit_on_texts(X)# convert to sequence of integersX = tokenizer。texts_to_sequences(X)

讓我們嘗試列印第一個樣本:

In [4]: print(X[0])[49, 472, 4436, 843, 756, 659, 64, 8, 1328, 87, 123, 352, 1329, 148, 2996, 1330, 67, 58, 4437, 144]

一堆數字,每個整數對應於詞彙表中的一個單詞,這正是神經網路所需要的。但是,樣本的長度不同,我們需要一種固定長度的序列。

結果,我們使用了keras。preprocessing。sequence。pad_sequences()函式,該函式在每個序列的開頭填充零。

# convert to numpy arraysX = np。array(X)y = np。array(y)# pad sequences at the beginning of each sequence with 0‘s# for example if SEQUENCE_LENGTH=4:# [[5, 3, 2], [5, 1, 2, 3], [3, 4]]# will be transformed to:# [[0, 5, 3, 2], [5, 1, 2, 3], [0, 0, 3, 4]]X = pad_sequences(X, maxlen=SEQUENCE_LENGTH)

您可能還記得,我們將SEQUENCE_LENGTH設定為100,這樣所有序列的長度都為100。

現在我們的標籤也是文字,但是我們將在這裡採取另一種方法,因為標籤只是“ spam”和“ ham”,我們需要對它們進行一次熱編碼:

# One Hot encoding labels# [spam, ham, spam, ham, ham] will be converted to:# [1, 0, 1, 0, 1] and then to:# [[0, 1], [1, 0], [0, 1], [1, 0], [0, 1]]y = [ label2int[label] for label in y ]y = to_categorical(y)

我們在這裡使用了keras。utils。to_categorial(),它的名字如其名,讓我們嘗試列印標籤的第一個樣本:

In [7]: print(y[0])[1。0, 0。0]

這意味著第一個樣品是正常郵件。

接下來,讓我們將訓練和測試資料進行混洗和拆分:

# split and shuffleX_train, X_test, y_train, y_test = train_test_split(X, y, test_size=TEST_SIZE, random_state=7)

四、建立模型

現在我們準備構建模型,通用架構如下圖所示:

在Python中如何使用Keras識別垃圾郵件

網路架構第一層是預訓練的嵌入層,它將每個單詞對映到實數的N維向量(EMBEDDING_SIZE對應於該向量的大小,在這種情況下為100)。具有相似含義的兩個單詞往往具有非常接近的向量。

第二層是帶有LSTM單元的遞迴神經網路。最後,輸出層是2個神經元,每個神經元對應於具有softmax啟用功能的“垃圾郵件”或“正常郵件”。

讓我們從編寫一個函式來載入預訓練的嵌入向量開始:

def get_embedding_vectors(tokenizer, dim=100):embedding_index = {}with open(f“data/glove。6B。{dim}d。txt”, encoding=’utf8‘) as f:for line in tqdm。tqdm(f, “Reading GloVe”):values = line。split()word = values[0]vectors = np。asarray(values[1:], dtype=’float32‘)embedding_index[word] = vectorsword_index = tokenizer。word_indexembedding_matrix = np。zeros((len(word_index)+1, dim))for word, i in word_index。items():embedding_vector = embedding_index。get(word)if embedding_vector is not None:# words not found will be 0sembedding_matrix[i] = embedding_vectorreturn embedding_matrix

注意:為了正確執行此功能,您需要下載GloVe,下載地址:http://nlp。stanford。edu/data/glove。6B。zip 解壓縮並放入“ data”資料夾,我們將在此處使用100維向量。

讓我們定義構建模型的函式:

def get_model(tokenizer, lstm_units):“”“Constructs the model,Embedding vectors => LSTM => 2 output Fully-Connected neurons with softmax activation”“”# get the GloVe embedding vectorsembedding_matrix = get_embedding_vectors(tokenizer)model = Sequential()model。add(Embedding(len(tokenizer。word_index)+1,EMBEDDING_SIZE,weights=[embedding_matrix],trainable=False,input_length=SEQUENCE_LENGTH))model。add(LSTM(lstm_units, recurrent_dropout=0。2))model。add(Dropout(0。3))model。add(Dense(2, activation=“softmax”))# compile as rmsprop optimizer# aswell as with recall metricmodel。compile(optimizer=“rmsprop”, loss=“categorical_crossentropy”,metrics=[“accuracy”, keras_metrics。precision(), keras_metrics。recall()])model。summary()return model

上面的函式構造了整個模型,我們將預訓練的嵌入向量載入到Embedding層,並設定trainable = False,這將在訓練過程中凍結嵌入權重。

新增RNN層後,我們增加了30%的退出機會,這將在每次迭代中凍結前一層中30%的神經元,這將有助於我們減少過度擬合。

請注意,準確度不足以確定模型是否執行良好,這是因為該資料集不平衡,垃圾郵件樣本很少。因此,我們將使用精度和召回率指標。

讓我們呼叫該函式:

# constructs the model with 128 LSTM unitsmodel = get_model(tokenizer=tokenizer, lstm_units=128)

五、訓練模型

我們需要用剛剛載入的資料來訓練該模型:

# initialize our ModelCheckpoint and TensorBoard callbacks# model checkpoint for saving best weightsmodel_checkpoint = ModelCheckpoint(“results/spam_classifier_{val_loss:。2f}”, save_best_only=True,verbose=1)# for better visualizationtensorboard = TensorBoard(f“logs/spam_classifier_{time。time()}”)# print our data shapesprint(“X_train。shape:”, X_train。shape)print(“X_test。shape:”, X_test。shape)print(“y_train。shape:”, y_train。shape)print(“y_test。shape:”, y_test。shape)# train the modelmodel。fit(X_train, y_train, validation_data=(X_test, y_test),batch_size=BATCH_SIZE, epochs=EPOCHS,callbacks=[tensorboard, model_checkpoint],verbose=1)

訓練已經開始:

_________________________________________________________________Layer (type) Output Shape Param #=================================================================embedding_1 (Embedding) (None, 100, 100) 901300_________________________________________________________________lstm_1 (LSTM) (None, 128) 117248_________________________________________________________________dropout_1 (Dropout) (None, 128) 0_________________________________________________________________dense_1 (Dense) (None, 2) 258=================================================================Total params: 1,018,806Trainable params: 117,506Non-trainable params: 901,300_________________________________________________________________X_train。shape: (4180, 100)X_test。shape: (1394, 100)y_train。shape: (4180, 2)y_test。shape: (1394, 2)Train on 4180 samples, validate on 1394 samplesEpoch 1/204180/4180 [==============================] - 9s 2ms/step - loss: 0。1712 - acc: 0。9325 - precision: 0。9524 - recall: 0。9708 - val_loss: 0。1023 - val_acc: 0。9656 - val_precision: 0。9840 - val_recall: 0。9758Epoch 00001: val_loss improved from inf to 0。10233, saving model to results/spam_classifier_0。10Epoch 2/204180/4180 [==============================] - 8s 2ms/step - loss: 0。0976 - acc: 0。9675 - precision: 0。9765 - recall: 0。9862 - val_loss: 0。0809 - val_acc: 0。9720 - val_precision: 0。9793 - val_recall: 0。9883

訓練結束:

Epoch 20/204180/4180 [==============================] - 8s 2ms/step - loss: 0。0130 - acc: 0。9971 - precision: 0。9973 - recall: 0。9994 - val_loss: 0。0629 - val_acc: 0。9821 - val_precision: 0。9916 - val_recall: 0。9875

六、評估模型

讓我們評估一下我們的模型:

# get the loss and metricsresult = model。evaluate(X_test, y_test)# extract thoseloss = result[0]accuracy = result[1]precision = result[2]recall = result[3]print(f“[+] Accuracy: {accuracy*100:。2f}%”)print(f“[+] Precision: {precision*100:。2f}%”)print(f“[+] Recall: {recall*100:。2f}%”)

輸出:

1394/1394 [==============================] - 1s 569us/step[+] Accuracy: 98。21%[+] Precision: 99。16%[+] Recall: 98。75%

以下是每個指標的含義:

準確度:正確預測的百分比。

召回率:正確預測的垃圾郵件的百分比。

精度:歸類為垃圾郵件的電子郵件實際上是垃圾郵件的百分比。

大!讓我們測試一下:

def get_predictions(text):sequence = tokenizer。texts_to_sequences([text])# pad the sequencesequence = pad_sequences(sequence, maxlen=SEQUENCE_LENGTH)# get the predictionprediction = model。predict(sequence)[0]# one-hot encoded vector, revert using np。argmaxreturn int2label[np。argmax(prediction)]

讓我們偽造垃圾郵件:

text = “Congratulations! you have won 100,000$ this week, click here to claim fast”print(get_predictions(text))

輸出:

spam

Okey,讓我們嘗試合法:

text = “Hi man, I was wondering if we can meet tomorrow。”print(get_predictions(text))

輸出:

ham

太棒了!這種方法是當前的最新技術,嘗試調整訓練和模型引數,看看是否可以改進。

要在訓練期間檢視各種指標,我們需要透過輸入cmd或terminal進入tensorboard:

tensorboard ——logdir=“logs”

轉到瀏覽器並輸入“ localhost:6006”,然後轉到各種指標,這是我的結果:

在Python中如何使用Keras識別垃圾郵件