如何用 MyEMS 数据 + CNN-LSTM 组合拳,把设备故障预警准确率干到 92%
很多搞工业信息化的朋友应该都有同感:设备的意外停机,永远是工厂里最烧钱、最让人抓狂的事之一。设备一停,产线跟着瘫,交付延迟、维修加急、备件空运,每一分钟都是真金白银在烧。
我去年在智能工厂现场做过一个预测性维护项目,思路不复杂,今天拿出来说说,核心就是围绕 MyEMS 这套开源的能源管理系统做数据底座,再用 CNN-LSTM 混合模型做故障趋势预测。项目落地之后,设备故障预警准确率稳定在 92% 左右,误报率压到了可控范围,算是从“坏了再修”真正切到了“坏了之前先拦下来”的模式。
这篇内容不堆理论,重点讲我们在现场怎么接数据、怎么构造训练集、CNN-LSTM 里的参数怎么敲定、以及那些文档里根本不会写的坑。如果你正在做设备健康管理、工业预测性维护、或者只是想把能源数据利用起来做点深度分析,这篇应该能帮你少走不少弯路。
1. 方案选型:为什么偏偏用 MyEMS + CNN-LSTM
先交代一下背景。项目所在的现场是一个中型机械加工车间,设备类型集中在车床、铣床、空压机、循环水泵这几类,总共 40 多台设备。之前的状态基本是“事后维修”和“定期点检”结合,现场老师傅靠耳朵听声音、拿手摸温度,经验很值钱,但没法规模化复制,而且单台设备真正出问题的时间窗口经常不在点检周期内。
1.1 核心思路:先要一套靠谱的数据底座
做预测性维护,第一件事不是训练模型,而是搞定数据。当时我们评估了几条路,包括直接从 PLC 走 OPC-UA 拉数据,或者自己写采集程序对接 Modbus,最后统一落到了 MyEMS 上。
选 MyEMS 的原因很现实:它本身就是开源的能源管理系统,已经有成熟的点位管理、数据采集、历史归档和告警通知能力。我们不需要重复造轮子去写数据存储和可视化,直接把设备的关键运行数据汇总到 MyEMS,再用它暴露出来的数据接口拿数据做算法实验就行。
MyEMS 的数据模型挺好理解,空间、能耗、虚拟表、点位管理,这套东西对设备运维场景来说稍微有点偏能源视角,但你只要把它想成“所有传感器数值和运行状态都可以归档到时间序列里”,思路一下就通了。我们在 MyEMS 里的做法是指定设备下的采集点,像功率、电流、三相电压、轴承温度、振动加速度、运行频率这些,统一按秒级或毫秒级采集,存进历史库。实测下来,MyEMS 对这些高频数据的存储和查询性能是撑得住的。
1.2 为什么模型选 CNN-LSTM,而不是纯 LSTM 或 Transformer
预测性维护说到底是个时间序列分类或回归问题。我们最终要输出的不是“设备温度是多少”,而是“这台设备未来 4 小时有没有大概率故障风险”。这类问题,现场数据有几个明显特点:
第一,数据是典型的多变量时间序列,有强时序依赖。第二,故障信号往往藏在短窗口内的趋势突变里,比如振动幅值从平稳突然爬升,电流波形出现窄幅高频毛刺。第三,样本量不大,现场负样本(故障样本)很少,模型不能过于复杂。
纯 LSTM 能搞定时序依赖,但它对局部特征的敏感度偏弱。设备故障前的早期征兆很多时候是短时间窗内的形态特征,比如频谱能量集中在某些频段、振动波形出现冲击脉冲,这些靠 LSTM 逐个时间步去记,效率不高。
Transformer 我们也试过,编码能力强,但问题是:数据量不大时非常容易过拟合,而且训练和推理的计算开销在现场的旧刀片服务器上扛不住。何况设备预警要的是稳定、快、可解释,不是把模型做得越复杂越显技术实力。
所以最后敲定 CNN-LSTM 混合结构:前面接几层一维卷积,负责从原始窗口里提取局部特征,把振动、电流、温度的短时模式压成特征序列,后面再接 LSTM 层去建模这些特征之间的时序关系,最后接全连接层输出分类概率。这个组合在工业时间序列上很经典,也经过了大量论文和工程项目的验证。
1.3 “92% 准确率”到底怎么定义的
这里必须说清楚口径,免得有人看到 92% 觉得是吹牛。我们在项目里定义的“预警准确率”是指在测试集上,模型预测“未来 4 小时会发生故障”的样本里,真正发生故障的比例,也就是精确率 Precision。但实际考核一个预测性维护系统,只看精确率远远不够。模型把故障样本漏掉了,后果更严重。所以我们在最终验收时同时盯三个指标:精确率、召回率、F1-Score。
92% 的准确率是在模型迭代后期、穿上阈值调整和误报抑制策略之后达到的水平。更细一点的数字是:测试集 6000 个窗口中,故障样本 912 个,模型成功识别 846 个,误报 72 个。召回率大概 92.8%,F1 约 0.92。不同设备类型单独看,滚动轴承类故障识别效果最好,润滑衰减类稍微差一点,具体后面详细讲。
2. 数据基础:从 MyEMS 里榨出高质量训练集
模型能不能用,七分靠数据,三分靠调参。这一步是整条链路里最费时间的,我们大概花了 60% 的精力在处理数据和标注上。好处是 MyEMS 把数据存储和查询这块做得很稳,节省了不少工作量。
2.1 MyEMS 数据模型与训练数据导出
MyEMS 里每个设备对应一组采集点,每个采集点有一条独立的历史数据记录。我们要做的第一件事是把 MyEMS 里的原始点表梳理清楚,跟现场设备台账对齐。这一步强烈建议用数据库直接导出,而不是依赖界面上的 Excel 下载,否则几十个设备、几十万个时间点,效率太低。
我们当时的做法是直接用 SQL 查询 MyEMS 的 energy 相关历史表,按时间范围把特定点位的数值取出来。查询条件大概是:
SELECT start_datetime, point_value FROM tbl_energy_value WHERE point_id = '设备A_振动加速度' AND start_datetime BETWEEN '2025-01-01 00:00:00' AND '2025-01-31 23:59:59' ORDER BY start_datetime;这里有个坑:MyEMS 的点位命名默认可能不是很直观,如果项目开始没做规范,后面提取数据会非常痛苦。我们踩过这个坑,一开始点位名有中文、有拼音、有英文缩写,最后统一成“设备编码_信号类型_物理位置”的格式,比如PUMP-A_VIB_DE表示 A 泵驱动端振动,建议做同类项目的朋友一开始就定好这个规范。
导出之后,每个设备会得到一张多列的时间序列表,时间戳做索引,每一列是一个测点。这一步做完,才是真正做特征工程的开始。
2.2 数据清洗与坏点处理
现场数据远没有教科书里那么干净。我们遇到过的情况包括:传感器瞬时掉线导致的空值、通信干扰产生的毛刺尖峰、设备停机期间采集到的不合理数值、还有维护人员手动复位导致的跳变。
处理逻辑分为几层。第一层是过滤停机时段,我们把设备运行状态这个点位作为 mask,如果设备没在运行,那这段时间的数据对故障训练没有意义。第二层是空值处理,对于连续小于 5 秒的空值,用线性插值补上;超过 5 秒的,整段剔除,不硬补。第三层是异常尖峰处理,用滚动窗口的中位数滤波,窗口设为 10 个采样点,把幅值超过 5 倍中位数绝对偏差的值砍掉。这一步非常关键,因为 CNN 对异常输入很敏感,一个裸尖峰就可能导致极高的误报。
另外还要做时间对齐。MyEMS 存储的时间戳可能存在毫秒级偏差,尤其在设备通过不同网关接入时比较明显。我们统一重采样到 1Hz 的固定频率,再开始后续处理。重采样不只是简单取均值,而是对振动这类高频信号取窗口内的最大值 + RMS 值,这样不会丢失冲击特征。
2.3 滑动窗口、标签制作与类别不平衡
模型输入不是单条数据,而是一段连续的时间窗口。我们用了滑动窗口,窗口长度定为 256 秒,也就是 256 个采样点,步长 32 秒。这个组合是我们在试验后敲定的:太短,捕捉不到故障发展的趋势;太长,训练样本数量不够,而且预警时效性会变差。
标签怎么打?这里需要设备维修记录配合。我们跟现场设备管理员把过去 8 个月的故障维修单逐条过了一遍,把每台设备故障发生的时间节点标注出来。然后按“未来 4 小时内是否发生故障”做二分类标签:如果一个窗口的结束时间点之后 4 小时内发生了故障,这个窗口标记为 1,否则为 0。这相当于让模型回答“看到这段数据,我判断这台设备未来 4 小时会不会出问题”,很容易跟现场的调度节奏结合。
类别不平衡是所有故障预测项目的通病。我们统计下来,故障窗口占总窗口比例不到 8%。直接用原始比例训练,模型会学成“全都预测正常”也能拿到很高的准确率,毫无意义。我们做了三件事:一是对故障窗口做过采样,用带随机噪声的复制扩充到占总样本的 25%;二是对正常窗口做了降采样,随机抽掉一部分,避免训练集过大导致每次迭代太慢;三是在损失函数里加了正类的权重,让模型把“漏报故障”视为更严重的错误。这三招组合下来,效果提升非常明显。
3. CNN-LSTM 核心细节:网络结构、调参、训练判据
模型本身不算复杂,但想把性能调出来,很多细节必须抠。这一节把网络结构、关键参数、训练时候的注意事项一次性讲透。
3.1 网络结构设计
我们的输入是一个 256×N 的矩阵,N 是参与训练的测点数量。一开始我们贪多,把所有能拿到的测点都塞进去,结果特征冗余反而拖垮了效果。后来做了一轮特征筛选,按故障相关性、信噪比、采样稳定性三个维度打分,最后保留了 8 个核心测点:电流、有功功率、驱动端振动、非驱动端振动、轴承温度、冷却液温度、主轴转速、负载率。这 8 个特征基本能覆盖机械故障和电气故障的大部分信号。
网络结构如下:
- Conv1D 层:64 个卷积核,kernel size 为 8,激活函数 ReLU
- MaxPooling1D:池化窗口 2
- Conv1D 层:128 个卷积核,kernel size 为 5
- 双向 LSTM 层:128 个隐藏单元,return sequences=False
- Dropout:0.3
- 全连接层:64 个神经元,ReLU
- 输出层:1 个神经元,Sigmoid
第一层大卷积核负责看较宽的时间窗内有没有趋势变化,第二层小卷积核去捕捉细节毛刺。卷积层的输出再接双向 LSTM,目的是同时利用前后上下文来理解特征序列。这个结构我们在 TensorFlow 里实现,大概长这样:
import tensorflow as tf def build_cnn_lstm_model(input_shape): inputs = tf.keras.Input(shape=input_shape) x = tf.keras.layers.Conv1D(filters=64, kernel_size=8, activation='relu', padding='same')(inputs) x = tf.keras.layers.MaxPooling1D(pool_size=2)(x) x = tf.keras.layers.Conv1D(filters=128, kernel_size=5, activation='relu', padding='same')(x) x = tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(128, return_sequences=False))(x) x = tf.keras.layers.Dropout(0.3)(x) x = tf.keras.layers.Dense(64, activation='relu')(x) outputs = tf.keras.layers.Dense(1, activation='sigmoid')(x) model = tf.keras.Model(inputs, outputs) model.compile( optimizer=tf.keras.optimizers.Adam(learning_rate=1e-4), loss='binary_crossentropy', metrics=['accuracy', tf.keras.metrics.Precision(), tf.keras.metrics.Recall()] ) return model3.2 关键超参数是怎么试出来的
训练过程踩了很多次坑,最终能出效果主要靠这几个参数的打磨。
第一个是学习率。开始直接用默认的 0.001,训练到第 10 轮就发现 loss 震荡严重,验证集上的精确率一直在 80% 附近上不去。降到 1e-4 之后,loss 曲线平滑了很多,20 轮以后精确率开始稳步爬升到 88% 左右。后来又尝试了带余弦退火的调度器,发现对这类小数据集反而容易过拟合,最后老老实实用固定学习率 + 早停。
第二个是 window size。我们对比过 64、128、256、512 四种窗口长度,结果很有意思:512 的窗口虽然包含了更长的故障发展趋势,但故障发生在窗口开头的话,其特征信息占比太小,反而不利于分类。256 是准确率和召回率的平衡点。
第三个是类别权重。故障窗口过采样之后,我们在损失函数里再给故障样本乘以 2 的权重,相当于硬性告诉模型“漏报一次故障比误报一次严重两倍”。这一步把召回率从 84% 拉到了 90% 以上。
另外,训练集和测试集的划分要考虑时间序列的特殊性。绝对不能随机切分,否则相邻窗口会被同时分到训练集和测试集,造成信息泄漏,测试出来的准确率高得离谱,一部署就露馅。我们按时间顺序切分:前 70% 的时间段做训练,中间 15% 做验证,最后 15% 做测试。这才是模拟真实在线推理的评估方式。
3.3 训练与验证中的判据选择
训练时的监控指标不能只看 loss 或 accuracy。遇到类别不平衡问题,accuracy 很容易骗人,我们以验证集的 F1-Score 作为模型保存的唯一标准。训练过程中用 EarlyStopping 回调,patience 设为 15 个 epoch,一旦验证 F1 不再提升就停止。最终模型大概在第 48 轮收敛,比我们预期的要慢,主要原因是样本量不大,模型学习速度偏慢,再加上用了 Dropout 和类别权重,loss 下降会比较平缓。这里别急,收敛慢不等于效果差。
还有一个容易被忽略的问题:batch size。我们试过 32、64、128 三种,64 的效果最稳定。batch 太小,梯度噪声大,训练不稳定;batch 太大,对小数据集来说内存占用高,而且容易陷入局部最优。实测下来 64 对 18000 个训练样本来说是最合适的。
4. 从训练到落地:完整实操流程与部署细节
模型在笔记本上跑出 92% 的准确率,这只是万里长征第一步。真正的挑战是如何把模型接到现场环境里,让它在设备真正坏掉之前发出预警,并且部署下去不能给现场工程师添麻烦。
4.1 端到端工作流是怎么组织的
我们的整体流程分五步,按节奏推进:
- 数据导出:通过 MyEMS 的 MySQL 数据库导出过去 8 个月的历史监测数据,按设备分组落成 CSV 或 Parquet 文件。
- 离线训练:在 Python 环境完成数据预处理、特征工程、模型训练与评估。这个阶段不需要碰现场系统,纯离线跑,反复调参。
- 模型导出:把训练好的 Keras 模型固化成 SavedModel 格式,里面包含了标准化参数和模型结构,部署端直接加载,不用重新训练。
- 在线推理:用 Python 脚本定时从 MyEMS 拉取最近 256 秒的测点数据,调用模型做推理,判断未来 4 小时是否有故障风险。
- 告警联动:推理结果传给规则引擎,超过阈值的设备进入预警状态,推送到 MyEMS 的告警通道,同时写入运维工单系统。
这里有一点在设计阶段就要想清楚:推理服务不能做成“一次性跑完就结束”的脚本,而是要常驻后台,每隔一定周期执行一次推理。我们的做法是写了一个后台任务,每 30 秒执行一次,对每台设备的实时窗口做一次预测。为什么 30 秒一次?这是现场运维节奏和服务器负载的平衡点。太频繁,服务器 CPU 占用会持续偏高;太稀疏,故障预警的时效性又跟不上。30 秒对大多数机械故障来说,完全够用。
4.2 实时推理与告警联动
在线推理比离线推理更麻烦的一点是:标准的计算方式要和训练时完全一致。训练时特征工程用的是整段数据的均值、方差做标准化,在线推理时就不能用未来数据来计算当前窗口的均值。我们的做法是把标准化参数(mean、std)在训练时一并保存下来,推理时直接调用。这个细节看着小,但很多人会在这一步出错,导致线上效果崩盘。
告警这块,我们用了一个简单但有效的策略:不单点触发,而是连续两次预测为故障才告警。第一次预测为故障,进入“待确认”状态;30 秒后下一个窗口如果依然是故障,才正式推送告警。这个“双确认”机制把误报率砍掉了差不多一半,代价只是预警延迟最多 30 秒,这个延迟对机械类故障来说完全可以接受。实战下来,这个机制极其实用,尤其是对一些信号质量不稳定的测点。
# 伪代码:双确认告警逻辑 window_data = fetch_realtime_data(device_id, window_size=256) pred_prob = model.predict(window_data) if pred_prob > threshold: if device_id in pending_alarm: push_alarm(device_id, f"预测未来4小时故障概率{pred_prob:.2%}") pending_alarm.pop(device_id) else: pending_alarm[device_id] = True else: if device_id in pending_alarm: pending_alarm.pop(device_id)你一定要看懂这段的逻辑:第一次超过阈值,先挂起,不打扰人;第二次确认后,才告警。这样就把单次毛刺干扰导致的偶发误报过滤掉了。
4.3 现场 Dashboard 的坑与取舍
给现场运维人员看的界面,和给管理层看的不一样。运维人员需要的是“哪台设备、什么问题、什么时候会坏、怎么处理”,不需要看模型结构图和 loss 曲线。我们基于 MyEMS 的看板能力做了日常巡检界面,重点展示三块内容:实时预测概率列表、预警设备详情、7 天故障趋势。设计上故意做了“极简”处理,故障概率高于 70% 的设备标红,50% 到 70% 标黄,低于 50% 正常显示。
这里必须说一个经验:不要过度依赖概率数值的绝对值。模型输出的 0.8 或者 0.6,并不代表“有 80% 的概率会坏”。概率值在阈值附近上下波动非常正常,现场人员容易盯着数字焦虑,我们要做的是用颜色和状态来淡化数值干扰,让他们只看“要不要处理”和“什么时候处理”。
5. 常见问题与排查技巧实录
这套系统上线初期,遇到的问题比想象中多。把几个典型问题和排查思路整理出来,供大家参考。
5.1 误报率压不下去怎么办
先分清误报是“数据问题”还是“模型问题”。我们最初误报率高达 20%,很多预警发生在设备完全正常的时段。排查后发现,相当一部分误报来自设备加减速过程本身。设备在启动、停机、换刀、变速时,振动和电流信号波动很大,模型很容易把这些正常工况变化识别成故障前兆。
解决办法是加了一个“工况识别”前置规则:只有当设备处于稳定运行状态(转速波动小于 5%、负载率在 30%-100% 区间)时,才把数据送入模型做预测。加减速和停机期间的推理结果直接跳过。这一条规则就把误报率降了一半多。
还有一部分误报来自传感器本身松动或现场电磁干扰。建议在数据清洗阶段就引入“传感器健康检查”,比如该测点在白天运行时段方差持续为零,就判定为传感器异常,而不是设备故障。
5.2 数据漂移与模型性能衰减
模型上线一个月后,我们发现准确率从 92% 慢慢滑到了 87%。排查后确认是数据漂移:现场换了批次润滑油后,振动频谱特征发生了偏移,而模型训练集里没有覆盖这种工况变化。
应对办法是建立模型性能监控机制。我们每周计算一次线上预测结果与实际故障的匹配情况,如果连续两周 F1 下降超过 3 个百分点,就触发重新训练流程。因为模型的离线训练流程已经自动化了,重新训练只需要导出新数据、跑一遍 pipeline、验证效果、更新 SavedModel,半天时间就能完成。预测性维护不是一锤子买卖,模型一定要有迭代机制。
5.3 现场算力不够的降级方案
有些工厂服务器配置很低,没有 GPU,跑起 LSTM 推理来延迟很高。我们的经验是:如果推理延迟超过 2 秒,就得考虑降级方案。第一步,把 LSTM 隐藏单元从 128 降到 64,看准确率损失多少;第二步,把 Conv1D 的通道数减半,观察 F1 变化;第三步,如果还不行,就考虑一套完全轻量的替代方案,比如用 XGBoost 配合统计特征来做故障分类。
实测下来,XGBoost 在同样的特征工程下能到 85% 左右的准确率,虽然不如 CNN-LSTM,但对于算力实在受限的场景,这是一个非常务实的备份方案。我的建议是任何预测性维护项目都要保留一套“轻量模型 + 规则引擎”的保底手段,哪怕它只用来做系统降级和交叉验证,也很有价值。
最后说点体会。预测性维护这个事,模型确实重要,但真正决定项目成败的是数据质量和运维习惯。MyEMS 帮我们把数据底座打得很扎实,CNN-LSTM 帮我们把故障规律学了出来,但如果你没有一套能持续跟进设备状态、及时反馈维修结果的流程,再好的模型也会随着时间慢慢失准。所以做这类项目,千万别只盯着模型调参,多花点精力在现场的设备档案、维修记录、数据规范上,回报率远高于在模型上多抠一个点。