尧图精选

CNN+LSTM网络流量检测Python源码实战与调优指南

🕒 发布时间:2026/9/28 2:10:03 📁 来源:尧图网络
简介一份基于CNN与LSTM融合模型的网络流量检测系统Python源码面向计算机、人工智能、通信工程、电子信息等相关专业的学生与开发者可用于毕业设计、课程设计、作业提交或项目初期立项演示。项目代码经过实际运行验证功能稳定可直接运行体验也能基于现有结构二次开发扩展更多流量识别场景。压缩包共6个文件包含5个Python脚本和1个Markdown说明文档脚本按职责划分为数据预处理、数据加载、模型定义、训练测试与主程序入口等模块便于理解深度学习完整流程说明文档则提供项目使用指引。整体资源包仅5KB轻量精炼。目前已有1304人浏览学习尤其适合希望快速掌握CNN与LSTM在流量分类检测中如何落地的初学者借助该源码即可完成从数据准备到模型评估的完整实践流程。1. 基于 CNNLSTM 的网络流量检测系统这套 Python 源码到底能跑出什么要做一套网络流量检测系统 Python 源码课设项目最务实的路线就是把流量记录切成交互会话抽成数值特征矩阵再用 CNNLSTM 的组合去区分正常流量与攻击流量。CNN 负责抓取短窗口内的局部模式LSTM 负责承接会话之间的时序依赖两个模型一前一后刚好覆盖了“空间特征”和“时间特征”两条线。这个源码包包含预处理、数据加载、模型搭建、训练测试、统一入口共五个 Python 文件外加一份项目说明文档模块划分干净适合计科、人工智能、网络安全方向的在校学生拿来当课设或毕设底稿。也适合刚接触深度学习的开发者拿它理解一维卷积和循环神经网络在非图像任务上的配合方式。先说结论这源码值得下下来完整跑一遍因为它每个文件都能在答辩时讲出实际用途而不是一个黑匣子。2. 源码结构盘点五个 Python 文件如何串联成一条检测流水线先花几分钟把压缩包里的文件类型理清楚这一步能替你省掉后面至少一个小时的排查时间。压缩包里的文件不多但它不是那种几十个文件堆在一起的“全家桶”式源码而是按职责拆分好的模块化结构。拿到手先不要急着运行main.py先把文件之间的调用关系看清楚你就知道该从哪个文件开始读、哪个文件是入口、哪个文件只做数据准备。2.1 文件职责与运行顺序这是一个典型的“数据准备 → 数据加载 → 模型定义 → 训练评估 → 统一入口”的五段式结构。常见的课设代码会把所有逻辑塞进一两个文件里这个项目拆得比较规矩对答辩和二次修改都更友好。文件名职责关键点project说明.md项目说明文档拿到后先读里面一般会写明环境要求和运行顺序data_preprocess.py原始数据清洗与特征预处理去空值、去重、标签编码、归一化data_load.py批量加载数据并做窗口切分负责生成 LSTM 需要的三维输入张量model.py定义 CNNLSTM 网络结构卷积、池化、LSTM、全连接层的组装train_and_test.py训练、验证、测试的完整流程早停、学习率衰减、模型保存main.py统一运行入口调度上面四个模块按顺序执行我一般拿到这种项目会先打开main.py看它的 import 列表基本就能推断出数据流向。接着按“预处理 → 加载 → 组网 → 训练”的顺序读四个文件最后再回头读项目说明文档核对数据集来源和参数设置。不要反过来先抠模型结构因为模型输入要是没对上后面全是维度报错。2.2 从原始流量记录到分类标签的数据流这条数据流是这个项目最核心的一条主线答辩时如果能把它讲顺基本就能拿一个不错的分数。原始流量记录进来之后先是按会话切分每条会话抽出一组统计特征比如包长均值、包长方差、协议类型、端口号、标志位分布、时间间隔等。这些特征经过清洗和归一化之后变成一条固定长度的数值向量多个这样向量再按时间顺序叠成窗口矩阵送给 CNN 做局部特征提取。后续的处理顺序决定了模型为什么能workConv1D 先在小窗口内用卷积核扫出几组局部模式比如“连续三个短包后跟一个大包”这种特征MaxPooling 把时序长度压短再把压缩后的特征序列交给 LSTM 去建模更长时间上的依赖关系。先 CNN 后 LSTM 而不是反过来是因为卷积核能先把无关细节过滤掉把输入序列的长度压缩到原来的二分之一甚至四分之一LSTM 需要处理的时间步就少了训练速度更快梯度也更容易稳定。最后接一个全连接层和 softmax输出每个类别的概率。2.3 运行环境与硬性门槛源码没有标注强制框架版本但课程设计最常见的主选方案是 Python 3.8 到 3.10 加 TensorFlow 2.x模型代码风格按 Keras 的Sequential组装方式来写。如果你的环境里装的是 PyTorch对应关系也很直接Conv1D换成nn.Conv1dLSTM换成nn.LSTMMaxPooling1D换成nn.MaxPool1d其余结构不变。硬件门槛方面这个模型的参数量不算大。CNN 部分是一维卷积几个卷积核加起来也就几万到十几万参数LSTM 的参数量取决于units和输入维度64 个隐藏单元大约会产生两三万个参数显存压力比 CV 类项目小得多。纯 CPU 跑小数据集也能完成训练只是 LSTM 反向传播是串行的时间步一长就会慢得明显。我的建议是有 NVIDIA 显卡就装 GPU 版 TensorFlow没有就用batch_size32强制调小别追求一次把数据全部塞进去。3. 数据预处理与加载把流量记录变成模型能吃的三维张量很多第一次跑 CNNLSTM 流量检测的人最容易翻车的地方不在模型而在数据喂进去的那一刻。流量日志和图像不一样图像天然是二维矩阵而流量记录是一行行的 CSV你要自己决定把哪几列当作特征、哪几列当作标签、怎么切窗口、怎么归一化。这一步做不对模型结构再合理也训练不出来。3.1 data_preprocess.py 里那几个关键操作预处理模块一般按照“去脏数据 → 特征编码 → 归一化 → 保存中间结果”的顺序来。先处理空值和重复行因为在真实的网络流量记录里漏采、重复采集、超时记录非常普遍不清理直接训练loss 可能直接变成 NaN。协议类型这一类文本特征没法直接参与计算常见做法是用LabelEncoder把字符串映射成整数或者按协议族做 one-hot 编码看你的特征规模决定。归一化这一步我建议用MinMaxScaler而不是StandardScaler。网络流量统计特征有个特点不同特征的量纲差异极大比如包长在几十到几千字节之间波动而 TCP 标志位组合是一个 0/1 计数如果用标准归一化离群的大值会主导均值方差反而把正常包长的分布压缩得很厉害。MinMaxScaler把所有特征压到 0 到 1 之间数值范围统一卷积核初始化之后更容易收敛。下面是这一模块的典型实现# data_preprocess.py 中的核心预处理逻辑 import pandas as pd import numpy as np from sklearn.preprocessing import MinMaxScaler, LabelEncoder df pd.read_csv(traffic.csv, encodingutf-8) df df.replace([np.inf, -np.inf], np.nan).dropna().drop_duplicates() # 标签编码Normal - 0, Attack - 1 label_encoder LabelEncoder() df[Label] label_encoder.fit_transform(df[Label]) # 选出所有数值特征列排除标签列和编号列 feature_cols [c for c in df.columns if c not in [Label, Flow_ID]] # MinMax归一化把每个特征压到[0,1] scaler MinMaxScaler() df[feature_cols] scaler.fit_transform(df[feature_cols]) # 保存归一化后的结果和编号器后续加载和预测还要用 df.to_csv(traffic_processed.csv, indexFalse)关键逻辑说明replace([np.inf, -np.inf], np.nan).dropna()这三步连写是先处理极大值和缺省值再删除脏行顺序不能反如果先删行再替换NaN 行根本查不出来。LabelEncoder必须在全部数据上fit不能只对训练集部分调用否则测试集里出现新类别会直接报错。scaler也要保存下来预测新样本时必须用同一套标准化参数否测归一化分布不一致模型预测结果基本是废的。3.2 data_load.py 的滑动窗口切分LSTM 的输入要求是三维张量(batch_size, timesteps, n_features)但预处理之后的数据是二维表格(样本数, 特征数)中间差了一个维度这就是data_load.py要解决的窗口切分问题。窗口切分的原理是把连续若干条会话记录叠成一个时间切片用前window_size个时间步的特征去预测当前窗口的流量类别。这样 CNN 和 LSTM 才能看到“特征的局部组合”和“特征随时间的演化”而不是孤立地看每一条流量。# data_load.py 中的滑动窗口切分逻辑 import numpy as np from sklearn.model_selection import train_test_split def make_windows(X, y, window_size10, step5): Xs, ys [], [] for i in range(0, len(X) - window_size, step): Xs.append(X[i:i window_size]) # 截取一个时间窗口 ys.append(y[i window_size - 1]) # 标签取窗口内最后一条 return np.array(Xs), np.array(ys) # 加载预处理后的数据 processed np.loadtxt(traffic_processed.csv, delimiter,, skiprows1) X, y processed[:, :-1], processed[:, -1].astype(int) X_windows, y_windows make_windows(X, y, window_size10, step5) # 按7:3划分训练集与验证集保持类别比例 X_train, X_val, y_train, y_val train_test_split( X_windows, y_windows, test_size0.3, stratifyy_windows, random_state42 )参数window_size10表示每个样本包含 10 条连续会话记录step5表示窗口之间重叠 5 条重叠的目的是不丢连续模式也相当于一种数据增强。窗口长度这个参数值得调它直接决定 LSTM 看到的时间跨度窗口太短抓不到长周期攻击模式太长则训练速度下降且容易过拟合。stratifyy_windows很关键它保证划分后每一类流量在两个集合里的比例一致不会因为随机划分导致验证集里某类样本缺失。运行完这段X_train的形状应该是(样本数, 10, 特征数)喂给模型之前可以在打印一行确认形状省得后面维度报错。3.3 类不平衡的隐患网络流量数据集里最现实的问题就是类不平衡正常流量数量远大于攻击流量在多数公开数据集里能占到八成以上。如果你不做任何处理模型会学到“全预测为正常类”准确率照样很高但攻击样本一条都识别不出来这种模型在答辩现场就是靶子。常见做法有两个一是在train_test_split之后给少数类更大的类权重二是对少数类做重采样。类权重的方式比较省事直接在训练时给损失函数加权让模型把预测错少数类的代价放大# 按样本数量反比计算各类权重 from sklearn.utils.class_weight import compute_class_weight class_weights compute_class_weight(balanced, classesnp.unique(y_train), yy_train) class_weight_dict {i: w for i, w in enumerate(class_weights)}这段代码里compute_class_weight会自动把少数类的权重拉高。如果正常类占 80% 而攻击类占 20%那么攻击类的权重会接近正常类的 4 倍模型在训练时会更注意少数类样本。如果你发现加权之后模型仍然偏向多数类再把window_size重叠率从 5 下调到 2让少数类样本被更多窗口覆盖也能缓解一点。4. 模型设计与训练评估Conv1D 抓局部模式LSTM 承接时序依赖模型结构是这个项目的灵魂也是答辩时老师最爱追着问的部分。你要能讲清楚三件事为什么用 CNN、为什么用 LSTM、为什么把两者串起来。只贴代码不讲原理不行因为你改成任意一个别的结构都能跑但随机初始化一组普通全连接层和这个组合模型的差距只有在评估环节才能真正体现出来。4.1 model.py 里的网络结构怎么组装Keras 风格下这个模型的典型写法是Sequential顺序堆叠一层一层的看非常直观。第一层用Conv1D卷积核在特征维度上滑动对流量特征序列做局部提取接着过BatchNormalization稳定激活分布再用MaxPooling1D压缩时序长度压缩后的序列进入LSTM层做时序建模最后接Dropout和全连接层输出分类概率。# model.py 中的 CNNLSTM 结构定义 from tensorflow.keras.models import Sequential from tensorflow.keras.layers import ( Conv1D, BatchNormalization, MaxPooling1D, LSTM, Dense, Dropout, Activation ) def build_cnn_lstm_model(window_size, n_features, n_classes): model Sequential([ # 一维卷积128个卷积核感受野为3 Conv1D(filters128, kernel_size3, paddingsame, input_shape(window_size, n_features)), BatchNormalization(), Activation(relu), MaxPooling1D(pool_size2), # LSTM承接时序建模输出最后一步的隐藏状态 LSTM(units64, return_sequencesFalse), Dropout(0.5), Dense(unitsn_classes), Activation(softmax) ]) return model model build_cnn_lstm_model(window_size10, n_features78, n_classes2) model.summary()这里每个配置都有讲究。kernel_size3是最常用的一维卷积核大小感受野覆盖当前特征点相邻三个时间步的局部组合比 5 或 7 更小的参数量就能捕捉到“短包短包大包”这类局部流量模式而且堆叠多层之后感受野会变大不需要一开始就用大卷积核。filters128是课设项目的稳妥起点往上加到 256 精度提升有限但训练时间翻倍往下减到 64 也能跑但拟合能力弱一些。MaxPooling1D(pool_size2)这一步很多新手会漏掉它把时间步压缩一半LSTM 要处理的步数直接减少训练速度提升接近一倍而且能抑制局部过拟合。return_sequencesFalse表示 LSTM 只输出最后一个时间步的隐藏状态再接全连接层分类。如果源码是 PyTorch 版本这个结构的对应关系是nn.Conv1d、nn.BatchNorm1d、nn.MaxPool1d、nn.LSTM最后加nn.Linear和nn.LogSoftmax。核心逻辑一致只有维度排布上 PyTorch 默认格式是(batch, channels, length)Keras 是(batch, length, features)迁移的时候需要permute一下。还有一个容易纠结的点是上不上双向 LSTM双向确实能提升几个百分点的精度但训练时间和参数量翻倍课设项目我建议先把单向跑通有余力再改双向。4.2 train_and_test.py 的训练配置与超参数训练流程配置直接决定模型能不能收敛以及收敛之后会不会过拟合。单看准确率不管训练曲线是很多课设翻车的根源。这里用三个回调函数配合可以做到一边训练一边自动止损# train_and_test.py 中的训练配置 from tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau, ModelCheckpoint callbacks [ # 验证损失连续10轮不降就停止同时恢复最佳权重 EarlyStopping(monitorval_loss, patience10, restore_best_weightsTrue), # 验证损失平台期时把学习率降半最低降到1e-5 ReduceLROnPlateau(monitorval_loss, factor0.5, patience5, min_lr1e-5), # 每轮保存验证损失最小的模型权重 ModelCheckpoint(best_model.h5, monitorval_loss, save_best_onlyTrue) ] model.compile( optimizeradam, losssparse_categorical_crossentropy, # 多分类标签直接用整数 metrics[accuracy] ) history model.fit( X_train, y_train, validation_data(X_val, y_val), epochs50, batch_size64, callbackscallbacks, class_weightclass_weight_dict, shuffleTrue )这套配置里的几个超参数是循序渐进的结果。epochs50不是让你真跑满 50 轮而是给一个上限配合patience10让模型在验证损失不再下降的 10 轮之后自动停止既不错过最佳点又不过度训练。ReduceLROnPlateau很实用Adam 虽然自适应学习率但训练后期仍然会出现验证损失震荡不下的情况factor0.5把学习率从 0.001 降到 0.0005再到 0.00025能帮模型跨过平台期。batch_size64对大多数课设机器是安全的显存不够就降到 32。class_weightclass_weight_dict接了上一章算出的类权重处理不平衡数据这一步不能省。4.3 评估阶段要看哪些指标训练完之后直接用model.evaluate看准确率是远远不够的。流量检测场景里正常类样本占大头就算模型把所有样本都判成正常类准确率也能到 80% 以上但这个模型没有任何实际价值。正确做法是把预测结果和真实标签导出计算混淆矩阵和精确率、召回率、F1from sklearn.metrics import classification_report, confusion_matrix y_pred np.argmax(model.predict(X_val), axis1) print(classification_report(y_val, y_pred, target_names[Normal, Attack])) print(confusion_matrix(y_val, y_pred))看结果的时候重点关注攻击类的召回率和 F1。召回率表示“真实攻击流量里被识别出来的比例”漏报一次攻击的代价比误报一次正常流量大得多所以我一般会盯着攻击类召回率是否在 90% 以上。如果精确率和召回率差距很大说明模型置信度分布有问题可以调整分类阈值不一定要非得用默认的 0.5。答辩时能讲清漏报和误报的权衡比报一个 99% 的准确率更有说服力。5. 避坑排查训练不收敛、预测全一类的五个常见翻车点写 CNNLSTM 流量检测这种项目真正花时间的地方不是搭模型而是调试那些“看起来跑通了但结果明显不对”的状态。我把这个领域常见的问题整理成五条踩坑记录每条都按现象、原因、解决三个步骤写照着排查能省不少时间。5.1 训练与评估阶段的三个经典坑第一条loss 变成 NaN。现象是训练刚开始几轮 loss 突然变成nanaccuracy 跟着卡死不动最终权重全部失效。原因通常是输入数据里有 NaN 或 Inf常见于流量日志中异常大的时间戳或包长被直接读入还有一个可能是学习率设得太大梯度更新一步跨过了有效区域。解决的顺序是先确认数据干净在预处理里强制df.replace([np.inf, -np.inf], np.nan).dropna()如果数据没问题再在compile时给优化器加上梯度裁剪把 Adam 的clipnorm设为 1.0然后学习率从 0.001 降到 0.0001 试一轮这组操作能解决大多数 NaN 问题。第二条验证集全部预测成同一类。现象是训练集准确率一路走高但拿到测试集上一看所有样本都被预测为正常流量攻击类别一个都没识别出。原因基本可以断定是类不平衡模型发现只要全猜多数类就可以拿到很高的训练准确率于是收敛到了这种“偷懒”的解。我一般的处理是加class_weight把少数类的损失权重拉高如果效果不明显再尝试对少数类样本做简单的复制过采样把攻击类样本复制两到三倍让训练集里两类比例从 1:9 拉到 1:3 左右。第三条训练 loss 下降但验证 loss 剧烈震荡。现象是训练曲线稳定向下验证曲线像锯齿一样大起大落最终早停触发模型停在了一个不稳定的权重上。原因多半是batch_size太小每个 batch 的梯度方向差异太大导致参数更新忽左忽右另一个常见原因是不同类别的样本在验证集里分布不均匀恰好某一批验证数据里攻击样本很多loss 就被少数样本拉高。解决方法是先把batch_size从 32 提到 64 或 128再确认train_test_split里用了stratifyy_windows保持类别比例最后设置一个固定的随机种子保证每次实验可复现。5.2 数据处理与环境的两个坑第四条模型输入维度报错。现象是训练时报错信息类似expected shape(None, 10, 78), found shape(None, 78)一看就是喂进去的数据少了一个维度。原因是没跑窗口切分直接把二维预处理结果送进了需要三维输入的网络。解决办法是回到data_load.py的make_windows确认输出形状打印一行print(X_train.shape)如果发现还是二维检查窗口切分函数的调用顺序有没有被执行到。实际项目里还有人把window_size错设为 0 或 1导致每个样本只包含一条会话LSTM 的时间步维度完全失效这种也要避免。第五条框架版本冲突导致无法导入。现象是import tensorflow时直接抛错或者报出numpy.core.multiarray failed to import。原因基本是系统环境里 NumPy 版本和 TensorFlow 预编译版本不匹配尤其是新装 Python 3.12 之后直接pip install tensorflow大概率撞上这类问题。我一般会新建一个独立虚拟环境把 Python 固定到 3.9装 TensorFlow 2.10 配 NumPy 1.23.5这个组合在课设场景里验证过多次兼容性最稳。Python 3.8 用户则可以把 NumPy 降到 1.24 以内。如果源码跑在 PyTorch 上常见坑是torch和torchvision版本不匹配用官方推荐的手动指定版本方式安装别用一条命令无脑装最新版。6. 进阶用法把训练好的最佳模型接到新的分类入口训练完成并保存了best_model.h5之后这个项目的实用价值才真正体现出来因为你可以脱离训练脚本独立加载模型对一个新样本做预测。这也是答辩时一个很好的加分点说明这不是只会在训练集上跑分的玩具而是一个可以接新数据的可用入口。加载模型的方式很简单load_model之后把新样本的特征向量按训练时的顺序组装好做同样的归一化和窗口切分然后predict输出每个类别的概率。# 新样本预测入口 from tensorflow.keras.models import load_model model load_model(best_model.h5) # 假设一条新流量的特征已经按训练时的列顺序排列好 new_feature np.load(new_flow_feature.npy) new_feature scaler.transform(new_feature.reshape(1, -1)) # 若原模型窗口大小为10则复制/滑窗构造10步输入 new_window np.tile(new_feature, (10, 1)).reshape(1, 10, -1) prob model.predict(new_window)[0] label int(np.argmax(prob)) print(预测标签:, label, 概率分布:, prob)这段代码里最容易踩的坑是scaler和窗口构造方式。scaler必须是预处理阶段训练好的同一个对象不能对新样本重新fit_transform否则归一化的分布基准完全不一致预测结果就没有参考意义。窗口构造这里用了最简单的时间维复制真实项目中你应该是从连续流量会话里切出最近 10 条记录再对齐特征列顺序。如果你想继续微调模型而不是只用现成权重可以试试冻结 CNN 部分只训练 LSTM 和全连接层在新数据集上做轻量迁移。常见做法是把前几层设为trainableFalse用较小的学习率 0.0001 再训练几个 epoch能在保留旧特征提取能力的同时适配新数据分布比从头训练快得多也稳得多。从那以后我每跑一个实训项目都强制先拿 200 条样本把整个链路走通再上全量数据这套流程已经帮我绕过了无数次“看似能跑实则白跑”的低级问题。你拿到这套源码后也按同样的顺序走一遍先预处理再窗口切分做一次最小训练确认链路通了再换全量数据调参希望帮到你。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联 返回资讯列表 →