KDDCUP99數據集處理(Keras)

環境:

Anaconda3-Spyder、python+keras+pandas+sklearn

數據集介紹

KDDCup99的原始數據來自於1998年的DARPA入侵檢測評估項目,所有的網絡數據來自於一個模擬的美國空軍局域網,網絡中加了很多模擬的攻擊。實驗的訓練數據爲7周的網絡流量,這些網絡流量包含有約500萬條網絡連接;實驗的測試數據爲2周的網絡流量,包含有約200萬條網絡連接。 對以上的數據集進行處理,形成了一個新的數據集。該數據集用於1999 年舉行的KDDCUP 競賽中,成爲著名的KDD99 數據集。雖然年代有些久遠,但KDD99數據集仍然是網絡入侵檢測領域的事實Benckmark,爲基於計算智能的網絡入侵檢測研究奠定基礎。
數據集中每個網絡連接被標記爲正常(normal)或異常(attack),異常類型被細分爲4大類共39種攻擊類型,其中22種攻擊類型出現在訓練集中,另有17種未知攻擊類型出現在測試集中,這樣設計的目的是檢驗分類器模型的泛化能力,對未知攻擊類型的檢測能力是評價入侵檢測系統好壞的重要指標。4種異常類型如表1所示。

KDDCup99訓練數據集中每個連接記錄包含了41個固定的特徵屬性和1個類標識,標識用來表示該條連接記錄是正常的,或是某個具體的攻擊類型。在41個固定的特徵屬性中,9個特徵屬性爲離散(symbolic)型,其他均爲連續(continuous)型。
屬性:
duration,protocol_type,service,flag,src_bytes,dst_bytes,land,wrong_fragment,urgent,ho,num_failed_logins,logged_in,num_compromised,root_shell,su_attempted,num_root,num_file_creations,num_shells,num_access_files,num_outbound_cmds,is_host_login,is_guest_login,count,srv_count,serror_rate,srv_serror_rate,rerror_rate,srv_rerror_rate,same_srv_rate,diff_srv_rate,srv_diff_host_rate,dst_host_count,dst_host_srv_count,dst_host_same_srv_rate,dst_host_diff_srv_rate,dst_host_same_src_port_rate,dst_host_srv_diff_host_rate,dst_host_serror_rate,dst_host_srv_serror_rate,dst_host_rerror_rate,dst_host_srv_rerror_rate,class
實例:
0,udp,private,SF,105,146,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0.00,0.00,0.00,0.00,1.00,0.00,0.00,255,254,1.00,0.01,0.00,0.00,0.00,0.00,0.00,0.00,normal.
0,udp,private,SF,105,146,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,2,0.00,0.00,0.00,0.00,1.00,0.00,0.00,255,254,1.00,0.01,0.00,0.00,0.00,0.00,0.00,0.00,snmpgetattack.
表1

步驟
(1)實驗數據的選取

在實驗研究中,使用KDDCup99中的網絡入侵檢測數據包kddcup_data_10percent做爲訓練集、corrected做爲測試集。kddcup_data_10percent數據包是對kddcup_data數據包(約490萬條數據記錄)10%的抽樣。

(2)選擇衡量問題成功的指標

因爲該實驗是處理的數據是網絡流量,輸入一條網絡流量,要能夠預測它所屬的類別(39種攻擊+normal),所以選擇衡量該模型性能的指標爲準確率,即正確分類的概率。

(3)確定評估方法

實驗選擇的數據集有近五十萬條網絡流量,數據量比較大,所以採用留出驗證集來評估,可以使用train_test_split()函數來劃分出15%的訓練集來充當驗證集。

(4)實驗數據預處理

下載的KDDCup99數據文件爲kddcup.data_10_percent_corrected和corrected。
第一步,用Notepad++打開另存爲.txt文件,方便python讀取。
第二步,利用python將.txt文件轉化爲.csv文件(train.csv和test.csv)。(tocsv.py)
第三步,利用python對數據進行預處理,包含數值替換文本、數值歸一化和標籤獨熱編碼。數值替換文本主要是將每條連接41個特徵值中值爲字符串的轉換爲數值形式。數值歸一化採用最值歸一化。預處理結束變爲4個文件(train_x.csv、train_y.csv、test_x.csv、test_y.csv)。(prehandle.py)

(5)搭建模型

搭建一個四層卷積神經網絡(卷積層+池化層+全連接層+softmax層)。因爲該網絡是要判斷出網絡流量所屬哪種類別(39種攻擊+normal),屬於多分類問題,所以在最後一層使用softmax層。
編譯時,需要指定三個參數。損失函數(loss function)使用categorical_crossentropy(多類對數損失,用於多分類問題)。優化器(optimizer)使用Adadelta。Adadelta在數據量比較大時,運算速度比較快。在訓練和測試過程中需要監控的指標(metric),本實驗只關心準確度,即正確分類的流量所佔的比例,所以選擇accuracy
訓練網絡,在Keras中是通過調用網絡的fit方法來完成——在訓練數據上擬合(fit)模型。並在fit函數參數中通過validation_data參數指定驗證集。本次實驗中,訓練集、驗證集和測試集如圖3所示。
圖3
始終監控訓練損失(loss)和驗證損失(val_loss),以及訓練準確率(acc)和驗證準確率(val_acc)。如果發現模型在驗證數據上的性能開始下降,那麼就出現了過擬合
下一階段就要開始正則化和調節模型,以便儘可能地接近理想模型,既不過擬合也不欠擬合。
不斷地調節模型(包括添加dropout、增加或減少層數、添加L1/L2正則化、嘗試不同的超參數等等)、訓練、在驗證集上評估、再再次調節模型,然後重複這一過程,直到模型達到最佳性能。
最後的模型及各參數如下
卷積層:輸出的維度(卷積濾波器的數量)filters=32;1D卷積窗口的長度kernel_size=3;激活函數使用Relu函數。池化層:採用最大池化,池化窗口大小pool_size=2。全連接層:128個節點,激活函數使用Relu函數。softmax層:40個節點,激活函數使用softmax函數。
該模型的監控訓練損失(loss)和驗證損失(val_loss),以及訓練準確率(acc)和驗證準確率(val_acc)可以使用繪圖代碼繪製出來,如圖4和圖5所示。
圖4,5
如圖4和圖5,訓練損失每輪都在降低,訓練精度每輪都在提升。但驗證損失和驗證精度並非如此:它們似乎在第12輪達到最佳值。爲了防止過擬合,可以在12輪之後停止訓練。
當我們對模型較爲滿意時,就可以在所有可用數據(訓練數據+驗證數據)上訓練,生成最終的模型。此時實驗數據如圖6所示。
圖6
然後進行測試,將測試集(test_x,test_y)傳入evaluate函數即可,最後評估一次。

(6)預測

將要進行預測的數據(test_x)傳入predict函數即可。

流程圖

圖7,8
圖9

具體代碼
文件格式轉換
import pandas as pd
col_names = ["duration","protocol_type","service","flag","src_bytes","dst_bytes","land","wrong_fragment","urgent","hot","num_failed_logins","logged_in","num_compromised","root_shell","su_attempted","num_root","num_file_creations","num_shells","num_access_files","num_outbound_cmds","is_host_login","is_guest_login","count","srv_count","serror_rate","srv_serror_rate","rerror_rate","srv_rerror_rate","same_srv_rate","diff_srv_rate","srv_diff_host_rate","dst_host_count","dst_host_srv_count","dst_host_same_srv_rate","dst_host_diff_srv_rate","dst_host_same_src_port_rate","dst_host_srv_diff_host_rate","dst_host_serror_rate","dst_host_srv_serror_rate","dst_host_rerror_rate","dst_host_srv_rerror_rate","label"]  #42個標識
data = pd.read_table("10_percent_corrected.txt",header=None, sep=',',names = col_names)
print(data.head(10))#查看前10行
data.to_csv("10_percent_corrected.csv")#另存爲csv文件
數據預處理
import pandas as pd
from sklearn.preprocessing import OneHotEncoder  
from pandas.core.frame import DataFrame
import numpy as np
def get_total_data():  #定義數值替換文本的函數
    data = pd.read_csv('10_percent_corrected.csv',header=None)
    #將源文件中3種協議類型轉換成數字標識
    data[1]=data[1].map({'tcp':0, 'udp':1, 'icmp':2})
    #將源文件中70種網絡服務類型轉換成數字標識
    data[2]=data[2].map({'aol':0, 'auth':1, 'bgp':2, 'courier':3, 'csnet_ns':4,'ctf':5, 'daytime':6, 'discard':7, 'domain':8, 'domain_u':9,'echo':10, 'eco_i':11, 'ecr_i':12, 'efs':13, 'exec':14,'finger':15, 'ftp':16, 'ftp_data':17, 'gopher':18, 'harvest':19,'hostnames':20, 'http':21, 'http_2784':22, 'http_443':23, 'http_8001':24,'imap4':25, 'IRC':26, 'iso_tsap':27, 'klogin':28, 'kshell':29,'ldap':30, 'link':31, 'login':32, 'mtp':33, 'name':34,'netbios_dgm':35, 'netbios_ns':36, 'netbios_ssn':37, 'netstat':38, 'nnsp':39,'nntp':40, 'ntp_u':41, 'other':42, 'pm_dump':43, 'pop_2':44,'pop_3':45, 'printer':46, 'private':47, 'red_i':48, 'remote_job':49,'rje':50, 'shell':51, 'smtp':52, 'sql_net':53, 'ssh':54,'sunrpc':55, 'supdup':56, 'systat':57, 'telnet':58, 'tftp_u':59,'tim_i':60, 'time':61, 'urh_i':62, 'urp_i':63, 'uucp':64,'uucp_path':65, 'vmnet':66, 'whois':67, 'X11':68, 'Z39_50':69})
    #將源文件中11種網絡連接狀態轉換成數字標識
    data[3]=data[3].map({'OTH':0, 'REJ':0, 'RSTO':0,'RSTOS0':0, 'RSTR':0, 'S0':0,'S1':0, 'S2':0, 'S3':0,'SF':1, 'SH':0})
    #將源文件中攻擊類型轉換成數字標識(訓練集中共出現了22個攻擊類型,而剩下的17種只在測試集中出現)
    data[41]=data[41].map({'normal.':0, 'ipsweep.':1, 'mscan.':2, 'nmap.':3, 'portsweep.':4, 'saint.':5, 'satan.':6, 'apache2.':7,'back.':8, 'land.':9, 'mailbomb.':10, 'neptune.':11, 'pod.':12,'processtable.':13, 'smurf.':14, 'teardrop.':15, 'udpstorm.':16, 'buffer_overflow.':17, 'httptunnel.':18, 'loadmodule.':19, 'perl.':20, 'ps.':21,'rootkit.':22, 'sqlattack.':23, 'xterm.':24, 'ftp_write.':25,'guess_passwd.':26, 'imap.':27, 'multihop.':28, 'named.':29, 'phf.':30,'sendmail.':31, 'snmpgetattack.':32, 'snmpguess.':33, 'spy.':34, 'warezclient.':35,'warezmaster.':36, 'worm.':37, 'xlock.':38, 'xsnoop.':39})
    #數值歸一化:最值歸一化           
    data[2] = (data[2]-data[2].min())/(data[2].max() - data[2].min())
    data[4] = (data[4]-data[4].min())/(data[4].max() - data[4].min())
    data[5] = (data[5]-data[5].min())/(data[5].max() - data[5].min())
    data[22] = (data[22]-data[22].min())/(data[22].max() - data[22].min())
    data[23] = (data[23]-data[23].min())/(data[23].max() - data[23].min())
    data[31] = (data[31]-data[31].min())/(data[31].max() - data[31].min())
    data[32] = (data[32]-data[32].min())/(data[32].max() - data[32].min())
    np.isnan(data).any()  #data裏是否存在nan
    data.dropna(inplace=True)  #刪除有缺失值的行
    return data
    
def get_target_data(): #定義標籤獨熱編碼的函數
    data = get_total_data()
    enc = OneHotEncoder(sparse = False) #獨熱編碼  sparse=False 直接生成array對象
    enc.fit([[0], [1], [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12], [13], [14], [15], [16], [17], [18], [19], [20], [21], [22], [23], [24], [25], [26], [27], [28], [29], [30], [31], [32], [33], [34], [35], [36], [37], [38], [39]]) #有40種元素,說明用40個狀態位來表示
    result = enc.transform(data[[41]]) #就是將data[41]這個特徵轉換成one-hot編碼
    return DataFrame(result)
def get_input_data(): #返回x
    data = get_total_data()
    del data[41]
    return data
    
if __name__ == '__main__':
    data_input = get_input_data()    #獲取x
    data_input.to_csv('train_x.csv',header=None,index=None)
    data_target = get_target_data()  #獲取標籤
    data_target.to_csv('train_y.csv',index=None,header=None)
搭建網絡
import time 
start = time.time()

import keras
from keras.models import Sequential  #序貫模型
from keras.layers import Dense    #全連接層
from keras.layers import Dropout  #隨機失活層
from keras.layers import Flatten  #展平層,從卷積層到全連接層必須展平
from keras.layers import Conv1D   #卷積層
from keras.layers import MaxPooling1D  #最大值池化
import pandas as pd
from keras import backend as k
from sklearn.cross_validation import train_test_split #隨機劃分爲訓練子集和測試子集
from keras.utils.vis_utils import plot_model
from keras.optimizers import SGD 
import matplotlib.pyplot as plt

batch_size = 128  #一批訓練樣本128張圖片
num_classes = 40  #有40個類別
epochs = 12   #一共迭代12輪

x_train = pd.read_csv('train_x.csv',header=None).values
y_train = pd.read_csv('train_y.csv',header=None).values
x_test = pd.read_csv('test_x.csv',header=None).values
y_test = pd.read_csv('test_y.csv',header=None).values

#從訓練集中手動指定驗證集
#x_train, x_dev, y_train, y_dev = train_test_split(x_train, y_train, test_size=0.15, random_state=2)

if k.image_data_format() == 'channels_first':
   x_train = x_train.reshape(x_train.shape[0], 1, 41)
   x_test = x_test.reshape(x_test.shape[0], 1, 41)
   #x_dev = x_dev.reshape(x_dev.shape[0], 1, 41)
   input_shape = (1, 41)
else:
   x_train = x_train.reshape(x_train.shape[0], 41, 1)
   x_test = x_test.reshape(x_test.shape[0], 41, 1)
   #x_dev = x_dev.reshape(x_dev.shape[0], 41, 1)
   input_shape = (41, 1)

model = Sequential()  #sequential序貫模型:多個網絡層的線性堆疊
#輸出的維度(卷積濾波器的數量)filters=32;1D卷積窗口的長度kernel_size=3;激活函數activation   模型第一層需指定input_shape:
model.add(Conv1D(32, 3, activation='relu',input_shape=input_shape))  #data_format默認channels_last
model.add(MaxPooling1D(pool_size=(2))) #池化層:最大池化  池化窗口大小pool_size=2
model.add(Flatten())  #展平一個張量,返回一個調整爲1D的張量
#model.add(Dropout(0.25))  #需要丟棄的輸入比例=0.25    dropout正則化-減少過擬合
model.add(Dense(128, activation='relu',name='fully_connected')) #全連接層
model.add(Dense(num_classes, activation='softmax',name='softmax'))

#編譯,損失函數:多類對數損失,用於多分類問題, 優化函數:adadelta, 模型性能評估是準確率
model.compile(loss='categorical_crossentropy', optimizer='adadelta', metrics=['accuracy'])
#運行 , verbose=1輸出進度條記錄      epochs訓練的輪數     batch_size:指定進行梯度下降時每個batch包含的樣本數
model.fit(x_train, y_train, batch_size= batch_size, epochs=epochs, verbose=1)
#history = model.fit(x_train, y_train, batch_size= batch_size, epochs=epochs, verbose=0, validation_data=(x_dev, y_dev))

"""
#模型的訓練損失(loss)和驗證損失(val_loss),以及訓練準確率(acc)和驗證準確率(val_acc)可以使用繪圖代碼繪製出來
def smooth_curve(points,factor=0.8): #定義使曲線變得平滑
    smoothed_points = []
    for point in points:
        if smoothed_points:
            previous = smoothed_points[-1]
            smoothed_points.append(previous * factor + point * (1 - factor))
        else:
            smoothed_points.append(point)
    return smoothed_points

loss = history.history['loss']
val_loss = history.history['val_loss']
epochs = range(1, len(loss) + 1)
plt.plot(epochs,loss, 'bo', label = 'Training loss')
plt.plot(epochs,val_loss, 'b', label = 'Validation loss')
plt.title('Training and validatio loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
plt.figure()
acc = history.history['acc']
val_acc = history.history['val_acc']
plt.plot(epochs, acc,'bo', label = 'Training acc')
plt.plot(epochs, val_acc, 'b', label = 'Validation acc')
plt.title('Training and validatio accuracy')
plt.legend()
plt.show()
"""
# 將測試集輸入到訓練好的模型中,查看測試集的誤差
score = model.evaluate(x_test, y_test, verbose=0,batch_size= batch_size)
print('Test loss:', score[0])
print('Test accuracy: %.2f%%' % (score[1] * 100))

#運行的時間
stop = time.time()
print(str(stop-start) + "秒")

# 神經網絡可視化
plot_model(model, to_file='D:/model21.png',show_shapes=True)

#輸出模型各層參數情況
model.summary()
結果

結果
模型參數
最後的網絡模型

分析

在第一次訓練模型時,將訓練集劃分出15%的數據充當驗證集,使得訓練集和驗證集爲同一分佈,訓練準確率和驗證準確率都較高。
第二次訓練模型時,每輪迭代訓練準確率也都較高,大部分都在99%左右。
而當我們使用從未出現過的數據(測試集)評估模型時,發現模型測試準確率爲92%左右,與我們訓練準確率存在一定的差距。我認爲主要原因是測試集與訓練集不是相同的分佈,測試集中存在17種訓練集中未出現過的攻擊類型,使得模型無法從訓練集中學習到這些攻擊類型的網絡流量的規則,但從另一角度來說,這說明模型還是存在對訓練集的過擬合,導致無法較好的泛化。

我還實現了一些其他網絡

BP神經網絡
BP網絡

model.add(Dense(64, input_dim=41, kernel_initializer='uniform', activation='relu',name='hidden_layer1'))  #指定第一層輸入維度 input_dim 來隱含的指定輸入數據的 shape。其他層的shape框架會自動推導
    model.add(Dense(64, kernel_initializer='uniform', activation='relu',name='hidden_layer2'))     #第一個參數units:該層的輸出維度。kernel_initializer:權值初始化的方法
    model.add(Dense(40, kernel_initializer='uniform', activation='softmax',name='output_layer')) 

還有更復雜的CNN
因爲電腦不給力,這個網絡已經跑的很吃力了,所以就不使用複雜的網絡模型了
複雜CNN
參考:
https://github.com/dendyikbc/kdd99-cnn-1
https://blog.csdn.net/com_stu_zhang/article/details/6987632
https://www.jianshu.com/p/05ec600a77eb
https://blog.csdn.net/zyxhangiian123456789/article/details/87445106
https://blog.csdn.net/asialee_bird/article/details/80491256
https://blog.csdn.net/u010916338/article/details/84067740

發佈了32 篇原創文章 · 獲贊 48 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章