You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

协议预测实现中LSTM模型准确率问题及优化建议问询

提升不平衡网络协议数据集的LSTM小类别预测准确率方案

问题背景

  • 数据集:140万行Wireshark捕获导出的CSV,仅使用Source、Destination、Protocol三个字段
  • 任务:基于LSTM学习前序流量的Source/Destination/Protocol序列关联,预测下一个数据包的Protocol
  • 现状:
    • 类别极度不平衡:TCP约100万条,UDP约20万条,其余协议样本量极少
    • 模型整体准确率0.8-0.85,但仅能准确预测TCP类别,小类别完全失效
    • 尝试过调整序列长度、epochs、batch size、缩小数据集、类别权重平衡,但小类别准确率仅0.3-0.4,整体准确率暴跌至0.2

核心问题分析

  1. 数据泄露:当前代码将当前步的Protocol独热编码加入输入特征,模型可直接利用该信息预测下一步,完全偏离任务目标(学习Source/Dest与Protocol的关联)
  2. 评估指标不合理:用整体Accuracy评估不平衡数据集,无法反映小类别的真实性能
  3. 类别不平衡处理不当:简单的类别权重设置可能过度压制多数类,导致整体性能暴跌,且模型梯度被多数类淹没
  4. 特征工程不足:IP地址的哈希方式未能充分保留语义信息

针对性优化建议与代码修改

1. 修复数据泄露问题

移除输入特征中的当前Protocol字段,仅保留Source和Destination的特征,确保模型学习的是Source/Dest序列与Protocol的关联,而非直接利用已知信息。

2. 更换评估指标

使用分类报告(Precision/Recall/F1)和混淆矩阵评估,聚焦小类别性能,替代无意义的整体Accuracy。

3. 改进类别不平衡处理

  • 使用class_weight='balanced'自动计算合理的类别权重,避免手动设置的偏差
  • 改用Focal Loss替代交叉熵损失,降低易分类样本(TCP)的权重,强制模型关注小类别

4. 优化特征工程

将IP地址转换为32位整数作为数值特征,比哈希更具区分度,保留IP的完整语义。

5. 模型与训练策略调整

  • 加入Dropout层防止过拟合
  • 使用自定义早停机制监控小类别F1分数,避免过拟合
  • 调整学习率,配合更多epochs平稳训练

修改后的示例代码

import pandas as pd
import numpy as np
from sklearn.model_selection import TimeSeriesSplit
from sklearn.preprocessing import LabelEncoder
from sklearn.metrics import classification_report, confusion_matrix
from keras.models import Sequential
from keras.layers import LSTM, Dense, Dropout, Bidirectional
from keras.utils import to_categorical
from keras.callbacks import EarlyStopping
from keras.losses import CategoricalFocalCrossentropy

# IP转32位整数函数
def ip_to_int(ip_str):
    try:
        octets = list(map(int, ip_str.split('.')))
        return (octets[0] << 24) + (octets[1] << 16) + (octets[2] << 8) + octets[3]
    except:
        return 0

# 加载并预处理数据
data = pd.read_csv('paketa.csv')
data = data.dropna()
data = data[(data['Protocol'] != 'IPv6') & (data['Protocol'] != 'MPTCP')]
unique_classes = data['Protocol'].unique()
print("Unique Protocols:", unique_classes)

# 特征工程:IP转整数并归一化
data['Source_int'] = data['Source'].apply(ip_to_int)
data['Dest_int'] = data['Destination'].apply(ip_to_int)

data['Source_int'] = (data['Source_int'] - data['Source_int'].min()) / (data['Source_int'].max() - data['Source_int'].min())
data['Dest_int'] = (data['Dest_int'] - data['Dest_int'].min()) / (data['Dest_int'].max() - data['Dest_int'].min())

# 构建序列:仅用Source和Dest特征,预测下一个Protocol
sequence_length = 10
sequences = []
targets = []

feature_cols = ['Source_int', 'Dest_int']
feature_data = data[feature_cols].values

for i in range(len(feature_data) - sequence_length):
    seq = feature_data[i:i+sequence_length]
    target = data.iloc[i+sequence_length]['Protocol']
    sequences.append(seq)
    targets.append(target)

X = np.array(sequences)
y = np.array(targets)

# 标签编码与独热编码
label_encoder = LabelEncoder()
label_encoder.fit(unique_classes)
y_indices = label_encoder.transform(y)
y_onehot = to_categorical(y_indices, num_classes=len(unique_classes))

# 构建LSTM模型
num_classes = len(unique_classes)
num_features = len(feature_cols)

model = Sequential()
model.add(Bidirectional(LSTM(128, return_sequences=True), input_shape=(sequence_length, num_features)))
model.add(Dropout(0.3))
model.add(LSTM(64))
model.add(Dropout(0.3))
model.add(Dense(num_classes, activation='softmax'))

# 使用Focal Loss处理类别不平衡
model.compile(
    loss=CategoricalFocalCrossentropy(gamma=2.0),  # gamma越大,小类别权重越高
    optimizer='adam',
    metrics=['accuracy']
)

# 自定义早停:监控小类别F1分数
class F1EarlyStopping(EarlyStopping):
    def __init__(self, val_f1_threshold=0.5, **kwargs):
        super().__init__(**kwargs)
        self.val_f1_threshold = val_f1_threshold

    def on_epoch_end(self, epoch, logs=None):
        val_pred = np.argmax(model.predict(self.validation_data[0], verbose=0), axis=1)
        val_true = np.argmax(self.validation_data[1], axis=1)
        report = classification_report(val_true, val_pred, output_dict=True)
        # 取样本量小于5万的小类别平均F1
        small_class_f1 = np.mean([report[str(i)]['f1-score'] for i in range(num_classes) if report[str(i)]['support'] < 50000])
        if small_class_f1 >= self.val_f1_threshold:
            self.model.stop_training = True
        super().on_epoch_end(epoch, logs)

# 时间序列拆分
tscv = TimeSeriesSplit(n_splits=2)

for train_index, test_index in tscv.split(X):
    X_train, X_test = X[train_index], X[test_index]
    y_train, y_test = y_onehot[train_index], y_onehot[test_index]

    # 训练模型
    early_stop = F1EarlyStopping(
        monitor='val_loss',
        patience=5,
        restore_best_weights=True,
        val_f1_threshold=0.6
    )

    history = model.fit(
        X_train, y_train,
        epochs=20,
        batch_size=64,
        class_weight='balanced',
        validation_split=0.1,
        callbacks=[early_stop],
        verbose=1
    )

    # 评估模型
    y_pred = np.argmax(model.predict(X_test, verbose=0), axis=1)
    y_true = np.argmax(y_test, axis=1)

    print("\n分类报告:")
    print(classification_report(y_true, y_pred, target_names=label_encoder.classes_))
    print("\n混淆矩阵:")
    print(confusion_matrix(y_true, y_pred))

内容的提问来源于stack exchange,提问作者GENERALE

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 08:54:53