ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

基于CNN与LSTM的网络入侵检测实战:UNSW-NB15数据集与机器学习流水线

基于CNN与LSTM的网络入侵检测实战:UNSW-NB15数据集与机器学习流水线 简介这是一份基于机器学习与深度学习实现的入侵检测完整项目主要面向计算机相关专业的学生可用于毕业设计、课程设计或期末大作业也适合希望进行实战练习的初学者。项目通过CNN、LSTM等模型对网络安全数据进行分类识别覆盖数据预处理、特征提取、不平衡处理、模型训练与预测等完整流程。资源共31个文件约26.58MB包含14个Python脚本、文档与说明文件、CSV数据文件、HDF5模型文件以及额外压缩的数据集代码注释清晰、结构分明能够帮助使用者快速理解并复现实验。项目内含CNN和LSTM两套模型实现并配有实验对比结果图片方便学习者直观评估模型性能。已有95人学习下载资料还附带项目文档、参考论文和使用说明特别是经过导师指导的高分设计实用性较强。1. 入侵检测为什么值得用 CNN 和 LSTM 一起做如果你的目标只是“网络流量分类”这个作业题单独跑一个随机森林就能交差但当你面对 UNSW-NB15 这种包含 9 类攻击的现代数据集时特征局部相关性、时序依赖和类别不平衡这三件事会把准确率卡住。这个基于 Python 的入侵检测项目把 CNN、LSTM 和传统机器学习流水线组织在同一套数据上补齐了项目文档、参考论文和使用说明既适合毕业设计、期末大作业也适合第一次接触网络入侵检测的开发者对照学习把“读 CSV 到出分类报告”的每个环节跑通。下面按模型拆开讲先看 CNN 这条线。2. CNN 检测攻击流量一维卷积如何处理网络特征2.1 数据集文件先搞清楚再动手解压 UNSW_NB15.zip 之后真正要用的其实是 data 目录下的三个文件train.csv、test.csv 和 2_feture.csv。train.csv 是持有完整类别标签的训练集test.csv 是同样结构但参与评估的测试集2_feture.csv 只有两个特征专门给 3d.py 做可视化演示用。UNSW-NB15 原始数据集的类别列 attack_cat 有十类Normal、Fuzzers、Analysis、Backdoor、DoS、Exploits、Generic、Reconnaissance、Shellcode、Worm训练时不要直接拿 label 的 0/1 顶替否则项目里那一堆多分类报告就失去了意义。import pandas as pd train pd.read_csv(data/train.csv) test pd.read_csv(data/test.csv) print(train.shape, test.shape) print(train[attack_cat].value_counts())先打印类别分布你会发现 Exploits 和 Generic 样本非常充裕而 Shellcode、Worm 只有很少的量级。这个发现直接决定后面要不要做不平衡处理也解释了项目里为什么单独写了 Process_Imbanlce.py。在准备特征矩阵时srcip、dstip、sport、dsport 这类标识列要从 X 里移除它们是地址信息而不是流量行为信息留着只会让模型记住个别 IP。2.2 cnn_pytorch.py 的核心模型结构cnn_pytorch.py 把模型封装成一个标准 PyTorch Module主结构是两段卷积加一个全连接头import torch.nn as nn class CnnIDS(nn.Module): def __init__(self, n_features49, num_classes10): super(CnnIDS, self).__init__() self.block1 nn.Sequential( nn.Conv1d(1, 64, kernel_size3, padding1), nn.BatchNorm1d(64), nn.ReLU(inplaceTrue) ) self.block2 nn.Sequential( nn.Conv1d(64, 128, kernel_size3, padding1), nn.BatchNorm1d(128), nn.ReLU(inplaceTrue), nn.MaxPool1d(2) ) self.head nn.Sequential( nn.Linear(128 * (n_features // 2), 256), nn.Dropout(0.5), nn.ReLU(inplaceTrue), nn.Linear(256, num_classes) ) def forward(self, x): x x.unsqueeze(1) # (batch, 1, n_features) x self.block1(x) x self.block2(x) x torch.flatten(x, 1) return self.head(x)这段代码里值得注意三个选择。第一是 nn.Conv1d 而不是 Conv2d因为一条流样本是一个 49 维向量一维卷积在特征维度上滑动kernel_size3 时每个输出位置看的是相邻三个特征的局部组合对 sbytes、sload 这类相邻协议字段比较敏感。第二是 padding1保证第一层输出长度不变MaxPool1d(2) 之后长度折半全连接层输入维度写成 128 * (n_features // 2)。第三是 Dropout(0.5) 放在全连接前UNSW-NB15 训练集数据量不小全连接层很容易把噪声记住加 dropout 是最直接的缓解方式。forward 里的 unsqueeze(1) 是让形状从 (batch, n_features) 变成 (batch, 1, n_features)不这么做 Conv1d 会按 batch 维报错这是第一次跑项目时最常见的报错点。2.3 训练前的缩放与编码不能省CNN 对输入尺度敏感。网络特征里 sbytes 可能到几十万而 ct_state_ttl 只有几十不归一化的话梯度方向会被大数值特征主导。项目里的 Min-max.py 和 Lable_encoder.py 配合完成这件事常见组合方式是from sklearn.preprocessing import MinMaxScaler, LabelEncoder from sklearn.model_selection import train_test_split num_cols X.select_dtypes(number).columns scaler MinMaxScaler() X_train[num_cols] scaler.fit_transform(X_train[num_cols]) X_test[num_cols] scaler.transform(X_test[num_cols]) enc LabelEncoder() y_train enc.fit_transform(y_train) y_test enc.transform(y_test)重点在 fit_transform 和 transform 的区别训练集用 fit_transform 学习每个特征的最小值和最大值测试集只能 transform否则会把测试集的信息泄漏进缩放器。类别列如 proto、service、state 属于字符串用 LabelEncoder 转成整数后也不需要再做 one-hot一维 CNN 能把整数当成有序尺度来学这算是一个省内存的做法。2.4 直接跑训练脚本要调哪些参数按 requirements.txt 装好依赖后训练入口在 cnn_train.py。项目给的是命令行调用方式pip install -r requirements.txt python cnn_train.py python cnn_predict.pycnn_train.py 内部一般会读取 data/train.csv 和 data/test.csv按前面步骤构造 DataLoader 后跑固定轮数。建议动手前先把超参数表对一遍参数项目常见设置说明batch_size128显存不够就降到 64epochs30UNSW-NB15 数据量足够30 轮已接近收敛lr0.001Adam 默认学习率表现稳定lossCrossEntropyLoss多分类任务标准选择optimizerAdam比 SGD 更容易调出理想结果训练时如果 loss 震荡不下降把学习率减半如果验证集准确率持续比训练集低不少先检查是不是 test.csv 里掺杂了和训练集重复的样本。提示所有模型必须共用同一份预处理后的数据版本先跑特征筛选脚本再训练否则几份报告的数值之间无法横向比较。3. LSTM 视角把 49 维特征向量当作一个时间序列3.1 为什么 CNN 之外还要单独做 LSTM一维 CNN 的优势是局部特征组合但 UNSW-NB15 的特征之间并不全是局部关系。dur 会影响 sbytes、sloadsttl 与 dttl 之间存在生命周期上的依赖这些跨字段的前后关系在随机森林里可以靠分裂规则捕捉在 CNN 里只能通过加深网络间接拟合。LSTM 的建模方式和它们都不同它把每条流当成一个长度为 49 的序列逐个特征地进入循环单元由门的机制决定哪些特征要记住、哪些要丢弃。所以项目里单独维护了 lstm_train.py 和 lstm_predict.py而不是只在 CNN 上微调卷积层。3.2 Dataset 构造把样本切成 (特征数, 1)LSTM 的输入形状是 (seq_len, batch, input_size)。在这个场景里最直接的做法是把特征维度当作 seq_len每个时间步输入一个数值input_size 就是 1import torch from torch.utils.data import Dataset class FlowSeqDataset(Dataset): def __init__(self, X, y): self.X torch.tensor(X, dtypetorch.float32) self.y torch.tensor(y, dtypetorch.long) def __len__(self): return len(self.X) def __getitem__(self, idx): sample self.X[idx].unsqueeze(1) # (n_features, 1) return sample, self.y[idx]这里 unsqueeze(1) 在特征维后面加一维得到 (49, 1)正好满足 LSTM 的 (seq_len, input_size) 要求。batch 维度由 DataLoader 自动补上最终进网络的张量是 (batch, 49, 1)。3.3 类别不平衡直接影响 LSTM 的训练目标UNSW-NB15 的测试集里Shellcode 和 Worm 的样本数量远小于 Exploits 和 Generic直接按原始分布训练LSTM 会倾向于把少数类全部判成 Normal。项目里的 Process_Imbanlce.py 处理的就是这件事。除了用 SMOTE 做重采样另一个更稳妥的方法是给损失函数加权import numpy as np from sklearn.utils.class_weight import compute_class_weight import torch.nn as nn classes np.unique(y_train) weight compute_class_weight( class_weightbalanced, classesclasses, yy_train ) weight torch.from_numpy(weight).float() criterion nn.CrossEntropyLoss(weightweight)compute_class_weight 会按各类样本占比反推权重样本越少的类别权重越大等价于在 loss 里把少数类错误放大。比 SMOTE 好在不会产生合成样本后续写论文解释模型行为时少一个争议点。3.4 LSTM 的超参数与训练注意事项LSTM 在入侵检测任务上比 CNN 更容易过拟合循环单元的参数共享让模型容量偏高。起点参数可以参考下面这张表参数建议值说明hidden_size64 或 128128 能容纳更多状态64 更稳num_layers22 层足够3 层以上收敛明显变慢bidirectionalFalse双向会让参数量翻倍建议先单向dropout0.2防止 LSTM 层之间的过拟合lr0.001比 CNN 更敏感波动时降到 0.0005训练时用同一个 train.csv、test.csvlstm_train.py 输出的 loss 曲线会呈现“先快速下降、后长时间小波动”的形状。这不是没收敛而是 LSTM 对少量边界样本持续敏感。此时不要一味加 epochs改成观察验证集 F1 是否还在涨更有效。4. 传统机器学习流水线特征筛选、归一化与分类对比4.1 相关性筛选Get_corr.py 为什么先于训练执行深度模型能自动从原始特征里学表示传统机器学习不行特征质量直接决定随机森林的上限。Get_corr.py 的角色是快速检查哪些数值特征与标签强相关。常见做法是先算 Pearson 相关系数再按阈值把明显无关的列排除import pandas as pd corr train.corr(numeric_onlyTrue)[label] selected corr[abs(corr) 0.2].index.tolist() print(fselected {len(selected)} features: {selected})threshold 取 0.2 左右比较合适UNSW-NB15 里很多特征和攻击类别是弱相关或不相关阈值太高会把对少数类仍然有判别力的特征误删。得到 selected 列表后get_feature.py 会把列表写到文件供 CNN 和 LSTM 共用同一份特征子集保证三个模型输入完全一致。4.2 RFP.py随机森林把特征重要性量化相关系数衡量的是线性关系特征重要性衡量的是模型训练后的实际贡献两者并不等价。RFP.py 用随机森林训练一轮把 Gini importance 排序后取前若干维作为正式输入from sklearn.ensemble import RandomForestClassifier rf RandomForestClassifier(n_estimators100, random_state42) rf.fit(X_train_scaled, y_train) imp pd.Series(rf.feature_importances_, indexX_train.columns) imp.sort_values(ascendingFalse).head(15).to_csv(top_features.csv)feature_importances_ 表示每个特征在所有决策树分裂中带来的不纯度下降总量值越大越重要。把 top_features.csv 保存下来有个额外价值论文里的特征选择章节可以直接引用这张表配合相关性热力图说明为什么最终只保留十几维特征。4.3 Min-max.py、Lable_encoder.py 与缺失值处理这两段脚本解决两类预处理问题。Min-max 把不同量纲的特征压缩到 [0,1]Lable_encoder 把 proto、state、service 这类字符串编码成整数。Min-max 正常写法是按列操作而不是按行df (df - df.min()) / (df.max() - df.min())如果这一行直接放在整个 DataFrame 上结果是对的但从 CSV 读进来时列顺序可能不一致发生顺序错乱。实际直接调用 sklearn 的 MinMaxScaler 更安全前面 2.3 已经演示过。缺失值方面UNSW-NB15 的 service 列存在大量空值处理方式是用占位字符串填充后再编码不要直接删除整行否则特征维度变了之后 cnn 和 lstm 的输入尺寸全部要跟着改。4.4 Process_Imbanlce.pySMOTE 的边界条件这个脚本的核心是对少数攻击类别做过采样。SMOTE 是常见选择from imblearn.over_sampling import SMOTE sm SMOTE(sampling_strategyauto, k_neighbors5, random_state42) X_res, y_res sm.fit_resample(X_train, y_train)sampling_strategyauto 会把所有类别的样本量对齐到最多那类k_neighbors5 表示生成样本时从 5 个近邻中插值。只对训练集做验证集和测试集保持真实分布否则评估结果偏乐观这也是答辩时评委最常追问的点。4.5 classify.py 与 3d.py分类对比与可视化classify.py 把随机森林、决策树、逻辑回归等传统模型放在同一份处理过的数据上输出 precision、recall 和 F1 的对比。3d.py 从 2_feture.csv 读取两维特征跑 PCA 投影到三维空间。它不参与正式评估主要作用是展示攻击样本在高维空间中的聚合情况放在论文实验章节里比一张表格更直观。cd ML python classify.py python 3d.pyclassify.py 跑完后会得到一个模型对比表正常情况下随机森林在多分类任务上会明显领先逻辑回归这个结果也解释了为什么项目把 RFP.py 单独放在特征工程环节。5. 复现项目的正确顺序和一个可落地的误报排查技巧5.1 按数据依赖顺序而不是文件名顺序执行项目根目录同时存在 cnn_pytorch.py、cnn_train.py、cnn_predict.py、lstm_xxx、ML 等多个入口第一次拿到源码先看 readme.md 里建议的顺序一般是这样python cnn_train.py python cnn_predict.py python lstm_train.py python lstm_predict.py cd ML python classify.py如果从数据流的角度重新排顺序应该是 Process_Imbanlce.py 放在归一化和标签编码之后3d.py 只能消费 2_feture.csv而 cnn_train.py、lstm_train.py 都要读取最终版本的 train.csv 和 test.csv。整条链路最后会得到两份分类报告一份来自深度学习模型一份来自传统模型两份报告合起来就支撑了论文里常写的“深度方法与传统方法对比”这一节。5.2 判断训练是否跑成功的三个信号第一看 loss 是否稳定下降第二看验证集准确率是否显著高于随机猜测多分类 10 类时高于 10%二分类时高于 50%第三看预测输出能否反推出 attack_cat 对应的类别名而不是只有 0 到 9 的整数。很多复现失败的原因都在下游训练时把 srcip、dstip 当作特征预测时没有丢弃或者测试集读进来列顺序和训练集不一致模型直接报维度错误。5.3 被漏检的样本才是写论文的素材只盯着 accuracy 和召回率项目看起来就是一个普通分类任务真正值得展开的是漏检样本长什么样。把预测结果落盘后做一次对比import pandas as pd y_pred pd.Series(model.predict(X_test), namepred) # model 为已训练的 cnn/lstm/rf 任一模型 y_true y_test.reset_index(dropTrue) df pd.concat([y_true, y_pred, test.reset_index(dropTrue)], axis1) wrong df[df[label] ! df[pred]] wrong.to_csv(wrong_cases.csv, indexFalse)这里 model 可以是前面任意一个模型X_test 是 test.csv 去掉标识列后的特征矩阵。打开 wrong_cases.csv按 label 分组统计 sbytes、dbytes、sload 等特征的平均值你会发现大部分漏检集中在连接短、流量小、协议状态异常的样本上。把这条规律写进论文的实验分析部分比堆十张准确率对比图更有说服力。本文还有配套的精品资源点击获取
返回列表