LogBERT:基于 BERT 的日志异常检测完整指南
【免费下载链接】logbertlog anomaly detection via BERT项目地址: https://gitcode.com/gh_mirrors/lo/logbert
凌晨三点被一条告警吵醒,翻日志发现又是一次误报——对常值班的人来说这画面不太陌生。LogBERT 用 BERT 做日志异常检测:先用模板解析把原始日志变成事件序列,再用"挖空补全"的方式训练模型,最后根据模型"猜不出"的 token 数量判定异常。它基于 PyTorch 从零实现了 BERT,并内置 HDFS、BGL、Thunderbird 三个公开数据集的完整实验流程,方便你把 DeepLog 等基线放在同一份数据上对比。
🌙 凌晨的误报,规则匹配为什么会扛不住
日志异常检测的传统做法基本是这几类,各自有明确短板:
- 手工写规则:
ERROR 出现次数 > 5 就告警。阈值定高了漏报,定低了天天误报;每来一种新日志格式,规则就要跟着改,维护成本全压在写规则的人身上。 - 浅层模型(LR、SVM、孤立森林、PCA 等):依赖人工构造的特征,遇到"单条日志都正常、连起来才异常"的情况基本没辙。
- LSTM 类序列模型(DeepLog):只能从前往后读,预测"下一个最可能是什么"。而异常往往要结合前后文一起看,单向预测天然吃亏。
LogBERT 把编码器换成双向的 BERT:序列里任何一个位置都能同时参考它前后的 token。这正好对应日志里很常见的一类异常——单条看都没问题,但组合起来的顺序或内容不对劲。
从下载到出 F1:HDFS 数据集上的完整流程
以 HDFS 为例,BGL、Thunderbird 目录下的步骤相同:
git clone https://gitcode.com/gh_mirrors/lo/logbert cd logbert conda create -f environment/environment.yml conda activate logbert cd HDFS sh init.sh # 下载原始日志到 ~/.dataset/hdfs/ python data_process.py # Drain 解析 + 生成训练/测试集 python logbert.py vocab python logbert.py train python logbert.py predict几个说明:
- 原始数据落在
~/.dataset/,中间结果和最终结果都在output/目录里。 train最多跑 200 个 epoch,10 个 epoch 无提升就早停;默认 4 层、4 头、hidden 256、batch 32。有 GPU 会快很多,纯 CPU 能跑但训练很慢。predict会自动在 0~1 里扫一个最优的序列级阈值,最后打印 TP/TN/FP/FN 和精确率、召回率、F1,不用手动调。
一条日志是怎么被判定为异常的
分三步看,每步都能对应到仓库里的一小段代码。
1. 原始日志变成事件序列
data_process.py用 Drain 解析器把日志逐行模板化:块号、IP、文件路径先被替换成*,结构相同的行归为同一个模板并分配一个 EventId。对 HDFS,事件再按 BlockId 串成序列——一个"会话"就是一个数据块的生命周期,正常/异常标签来自数据集自带的anomaly_label.csv,训练集只取正常块,异常块全部留到测试集。
2. 训练:随机挖空,让模型补全
预训练目标很朴素:随机 mask 掉 65% 的 token,让 BERT 根据上下文猜被挖掉的词,类似做填空题。模型见过足够多正常的日志序列后,对"正常的词该怎么排列"就有了感觉。
3. 判定:看模型"猜不出"多少词
预测时同样 mask 一部分 token。每个被 mask 的位置取模型置信度 Top 6 的候选,真实 token 不在里面就记为"未检测出"。一条序列里未检测出的比例超过 50%(seq_threshold=0.5),这条序列就判为异常。
这个思路比"输出一个概率"更好解释:你能直接看到是哪些词模型猜不出来,候选词又是什么。
📁 想读源码,从哪几个目录入手
| 目录 | 内容 |
|---|---|
| logparser/ | Drain、Spell 两个日志模板解析器 |
| bert_pytorch/model/ | 从零写的 BERT:注意力、嵌入、位置编码,日志专用结构在log_model.py |
| bert_pytorch/dataset/ | 词表构建、窗口采样、训练/验证切分 |
| bert_pytorch/trainer/ | 训练循环、早停、超球损失(Deep SVDD) |
| HDFS/、BGL/、TBird/ | 三个数据集各自的入口脚本,结构一致 |
| scripts/ | 原始日志下载脚本 |
每个数据集目录里除了logbert.py,还有deeplog.py、loganomaly.py和baselines.ipynb,跑基线不需要额外装别的东西。
和 LSTM 基线比,落地差异在哪
| 维度 | 规则/阈值 | DeepLog(LSTM) | LogBERT |
|---|---|---|---|
| 判定依据 | 命中规则即告警 | 单向预测下一词 | 双向上下文补全 |
| 新日志类型出现 | 要手写新规则 | 词表变了,需重训 | 词表变了,需重训 |
| 可解释性 | 规则本身就是原因 | 下一个词的概率 | 猜不出的词 + Top 6 候选 |
| 对序列模式的敏感度 | 低 | 中(只有前文) | 高(前后文都参考) |
| 数据要求 | 不需要数据,但要专家经验 | 正常日志序列 | 正常日志序列 |
| 算力与算力外成本 | 基本没有 | 训练推理都便宜 | 推理要载一个 4 层 BERT,训练建议有 GPU |
一句话总结:LogBERT 省掉的是写规则和调阈值的人力,换来的是更高的算力要求和一份必须维护的训练流程。
什么场景下值得用,什么时候不必用
比较适合:
- 有一批正常日志(最好带异常标签),想离线评估深度方法的效果;
- 异常体现在序列模式上,而不是单条报错;
- 需要在同一份数据上对比 BERT 与 LSTM 基线。
不太适合:
- 毫秒级实时告警的在线流——这套代码按离线评估写的,是批处理推理,接实时流要自己再包一层工程;
- 几乎没有历史日志可训练,模型没有内容可学;
- 只有纯 CPU 小机器又要跑大日志——能跑但很慢,
with_cuda=True是默认配置。
下一步可以做什么
三件事,按顺序来:
- 在同一个 HDFS 数据集上把基线跑一遍:
python deeplog.py vocab && python deeplog.py train && python deeplog.py predict,把 F1 和 LogBERT 放进同一张表。注意 DeepLog 需要把 vocab 步骤输出的词表大小手动填回脚本里的vocab_size。 - 换到 BGL 目录重复同样流程,观察模型在不同数据集上的表现差异。
- 想调整判定松紧:放宽
num_candidates(默认 Top 6)会减少误报,但可能漏掉更隐蔽的异常;调seq_threshold的扫描范围则改变序列级判定的严格程度。
【免费下载链接】logbertlog anomaly detection via BERT项目地址: https://gitcode.com/gh_mirrors/lo/logbert
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考