从Linux内核日志到故障预警:我是如何用PyTorch搞定天池智能运维赛题的
从Linux内核日志到故障预警:我是如何用PyTorch搞定天池智能运维赛题的
第一次打开那个包含490469行日志的CSV文件时,密密麻麻的布尔值列让我头皮发麻。这是天池平台智能运维竞赛提供的服务器内存故障数据,28列中24列都是代表不同故障模板的布尔标记。作为参加过三届Kaggle的老兵,我意识到这次挑战的独特之处——它不像结构化数据预测那样有明确的特征工程路径,更像是在一堆杂乱无章的服务器"呼救信号"中寻找规律。
1. 数据迷雾中的第一束光
原始数据中的memory_sample_kernel_log_*.csv文件记录着服务器内核抛出的各种错误信息,每个布尔列对应一个预定义的错误模板。但棘手的是,组织方明确说明这些模板不一定都与DRAM故障相关。我的第一个决策点出现了:是直接使用所有24个布尔特征,还是先做特征筛选?
关键数据预处理步骤:
def etl(path, agg_time):
data = pd.read_csv(os.path.join(PARENT_FOLDER, path))
data['collect_time'] = pd.to_datetime(data['collect_time']).dt.ceil(agg_time)
return data.groupby(['serial_number','collect_time'],as_index=False).agg('sum')
这个5分钟聚合函数成了我的突破口。将原始日志按服务器序列号和时间窗口聚合后,True/False被转换为计数,突然让数据有了时序特征的味道。但真正的转折点出现在分析标签分布时——正样本占比不足0.5%,典型的类别不平衡问题。
处理样本不平衡时,下采样多数类往往比过采样少数类更不容易导致过拟合
我最终选择保留全部布尔特征,原因有二:一是初赛时间有限;二是发现某些冷门模板(如3_hwerr_mce_l)在故障发生前出现频率会突然升高。这个直觉后来被证明是对的——在A榜取得了前3%的成绩。
2. 特征工程的蝴蝶效应
在实验室通宵的第三个晚上,我发现了原始方案的重大缺陷:直接对布尔值求和会丢失模板出现的先后顺序信息。于是诞生了第二版特征工程方案:
- 滑动窗口统计:计算每个5分钟窗口内各模板的累计出现次数
- 变化率特征:记录相邻时间窗口间各模板计数的变化幅度
- 组合特征:对常同时出现的模板组合(如
1_hwerr_e和2_hwerr_c)创建交叉特征
# 变化率特征示例
def add_delta_features(df):
for col in df.columns[2:-3]: # 排除非模板列
df[f'{col}_delta'] = df.groupby('serial_number')[col].diff().fillna(0)
return df
这个改进让模型AUC提升了0.15,但也带来了新问题——特征维度爆炸到72维。为解决这个问题,我不得不重构数据管道:
| 处理阶段 | 原始方案 | 优化方案 |
|---|---|---|
| 特征提取 | 24维布尔和 | 72维动态特征 |
| 特征选择 | 保留全部 | 基于互信息筛选 |
| 归一化 | 无 | RobustScaler |
3. 模型选择的艺术与科学
面对处理后的数据,我测试了三种架构:
- 基准MLP:简单的三层全连接网络
- LSTM:捕捉时序依赖关系
- 集成模型:MLP+LightGBM组合
最终选择MLP并非因为它最优,而是考虑到:
- 比赛对推理速度有严格要求
- 其他模型提升有限(<2%)但复杂度大增
- MLP更容易解释故障触发逻辑
class DRAMPredictor(nn.Module):
def __init__(self, input_dim):
super().__init__()
self.fc1 = nn.Linear(input_dim, 64)
self.bn1 = nn.BatchNorm1d(64)
self.fc2 = nn.Linear(64, 32)
self.dropout = nn.Dropout(0.3)
self.out = nn.Linear(32, 2)
def forward(self, x):
x = F.relu(self.bn1(self.fc1(x)))
x = self.dropout(F.relu(self.fc2(x)))
return self.out(x)
这个看似简单的网络包含几个关键设计:
- BatchNorm层加速收敛
- Dropout防止过拟合
- 输出层不做softmax(与CrossEntropyLoss配合)
4. 训练过程中的血泪教训
最初直接训练时,模型完全学不到有效模式。通过分析发现三个致命问题:
问题排查清单:
- 学习率过高(>0.01)导致损失震荡
- 没有早停机制导致过拟合
- 批量归一化层在验证集泄露
解决方案是引入渐进式学习率预热:
optimizer = torch.optim.AdamW(model.parameters(), lr=5e-4)
scheduler = torch.optim.lr_scheduler.OneCycleLR(
optimizer,
max_lr=1e-3,
steps_per_epoch=len(train_loader),
epochs=100
)
另一个突破是采用加权损失函数处理类别不平衡:
pos_weight = torch.tensor([10.0]) # 正样本权重
criterion = nn.BCEWithLogitsLoss(pos_weight=pos_weight)
在最终提交的模型中,这些技巧组合使用使得F1分数从0.31提升到0.68。但比赛结束后复盘时,我发现如果加入更多业务逻辑(如特定厂商服务器的故障模式差异),效果还能再提升5-8%。这让我深刻意识到:在工业场景中,领域知识有时比算法技巧更重要。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐
所有评论(0)