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

发布了34 篇原创文章 · 获赞 51 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_39480875/article/details/103782178
今日推荐