ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

MyEMS集成LSTM实现高精度电力负荷预测的完整实践

MyEMS集成LSTM实现高精度电力负荷预测的完整实践 在能源管理系统里负荷预测不是什么新鲜课题但真正能把它从论文搬到生产环境、还能稳定跑出效果的项目并不多。MyEMS 是个开源能源管理系统我这两年基于它做过不少二次开发其中最有价值的一块就是接入了 LSTM 神经网络做电力负荷预测项目验收时模型在测试集上的平均绝对百分比误差能控制在 5% 以内用我们内部常见口径来说就是预测准确率 95%。这个结果不是随手调一个 Python 库 fit 一下就能出来的背后涉及数据清洗、特征构造、模型训练、系统集成等一系列环节。这个内容对谁有用如果你正在做能源管理、电力负荷预测或者想在 MyEMS 这类开源平台里引入 AI 能力我的整套流程可以照着参考如果你刚接触 LSTM 时间序列预测也能从数据处理、训练细节和避坑经验里找到可以直接上手的思路。下面就从方案选型开始讲。1. 方案选型负荷预测在 MyEMS 里到底该怎么落地1.1 让数据从“记录”变成“预判”MyEMS 的核心能力很多比如采集电表数据、水表数据、分类分项能耗统计、设备监控等等。大部分客户用 MyEMS 还停留在“把数据存下来、把报表做出来”的阶段也就是看历史曲线、算同比环比。可一旦涉及节能改造、需求响应、容量管理光看历史就不够了必须提前知道下一小时、明天甚至下个星期的负荷是多少。负荷预测本质上是一个时间序列回归问题输入过去一段时间的负荷和其他相关变量输出未来时段的负荷值。比如要预测工厂明天上午 9 点的用电负荷就要把过去 7 天每 15 分钟一个点、每天 96 个点的数据都考虑进去。为什么 MyEMS 适合做这件事因为它已经把多能源、多站点的时序数据统一到了数据采集层有相对规整的计量点、能耗模型和时间维度模型需要的历史数据可以直接复用不需要从零搭建数据管道。当时我考虑过几个方案传统的时间序列模型如 ARIMA、指数平滑机器学习模型如 XGBoost、LightGBM以及深度学习模型如 LSTM、TCN。每个方法都能做预测但在实际能源项目中表现差异很大。ARIMA 对平稳性要求高负荷数据里节假日、天气、生产排班带来的非线性影响很难用差分方式完全消除XGBoost 这类模型擅长表格特征但它需要人工提供非常多的滞后特征和滚动统计特征特征工程稍微粗糙一点精度就往下掉。1.2 为什么选 LSTM 而不是 XGBoost 或传统时序模型LSTM 的全称是长短期记忆网络属于循环神经网络的一种改进结构。普通的循环神经网络在处理长序列时梯度在反向传播过程中会逐渐消失导致模型记不住太久之前的信息。LSTM 引入了一个“记忆单元”和三个门遗忘门、输入门、输出门。我一般给同事打比方说它就像是一个带着笔记本的人每看到一个数据点会先想想“哪些旧信息要忘记哪些新信息要记下来最后哪些要写进当前输出”。这套机制让它可以捕捉负荷数据里的短期波动和长期趋势。电力负荷本身有很强的日周期性、周周期性和季节性。一家工厂的工作日负荷曲线和休息日差别很大冬夏两季因为空调用电负荷又会出现整体抬升。LSTM 的好处是能把“昨天的同一时刻在某个水平、前两小时有上升趋势”这类时间依赖关系内化到网络权重里而不是只能靠人工去算滞后特征。当然LSTM 不是无敌的。它的训练时间比 XGBoost 长很多超参数也多。我当时坚持用它的原因是我面对的数据源足够长——MyEMS 里通常存了至少一年以上的历史能耗数据频率可以做到 15 分钟一个点。数据量越大LSTM 的优势越明显。如果你的项目只有几个月的日数据我反而建议先用 XGBoost 试一试没必要一上来就搭神经网络。在整个方案里我用 LSTM 做的是“短期负荷预测”重点是未来 24 小时时间粒度为 15 分钟或 1 小时。这个粒度能覆盖大多数客户的容量控制、需量管理和节能调度需求。如果只需要知道下个月的总用电量LSTM 未必是最合适的用周期性分解加回归会更稳。1.3 关于“95% 准确率”的定义先把这个数字说清楚避免大家误会。负荷预测是回归任务不是分类任务所以不好直接用“准确率”这种词。业界常用 MAPE也就是平均绝对百分比误差。如果一个预测值相对实际值偏了 2%一个偏了 6%平均下来就是 4%。MAPE 越低越好。我在项目里说的“95% 准确率”准确口径是预测结果在测试集上的 MAPE 低于 5%也就是说 1 - MAPE 95%。你如果习惯用 1 - MAPE 表示准确率也说得通但真正写报告时一定要备注清楚。另外还要看模型是否会因为预测值偏低导致 MAPE 虚高或虚低。负荷值如果接近零一个小偏差算成百分比就会被放大得很夸张。所以我评估模型时不只看 MAPE还会看每个预测点的误差分布以及是否有系统性的低估或高估。95% 这个数字是在工厂和商业建筑两个数据集上都验证过的结果不是只在某一个好预测的时段里挑出来的。2. 数据准备与特征工程影响预测精度的上游环节2.1 数据采集与清洗先把脏数据收拾干净很多人做 LSTM 一上来就写模型结构但我踩过不少次坑之后发现数据处理才是决定最终精度的主要因素。MyEMS 通过 Modbus、BACnet、M-Bus、HTTP API 等方式从电表、水表、传感器采集数据数据质量参差不齐。最常见的脏数据问题有三类漏采、跳变、重复值。漏采通常在网络抖动或设备离线时产生。MyEMS 内部有补传机制但不一定能覆盖所有点位。如果某一天停电电表数据会直接断档。对这种缺失值我的做法是先看缺失比例如果小于 5%用前后相邻点的线性插值处理如果连续缺失几个小时线性插值会严重失真我会尽量寻找同周期历史数据填补。比如今天早上 9 点到 10 点缺失可以用过去五个工作日对应的同一时段求平均值加一个噪声补偿或者直接用模型预测值补上但这样做要小心在验证阶段引入数据泄露。跳变是另一个高频问题。电流互感器故障、采集器重启、数据单位换算错误都会导致某一个点或者某一段数据的数值突然变成平时几十倍甚至出现负数。负数在电表数据里并不总是错误比如光伏并网点在发电量大于用电量时会显示负功率但普通配电支路出现负值就要特别警惕。处理跳变不能简单用全局阈值因为不同建筑、不同支路的负荷范围差异很大。我一般会先用四分位距法识别异常点再用一个滑窗把相邻时间点的变化率作为判断条件。如果变化率超过正常生产规律上限就标记成异常值再用插值修正。重复值相对好处理按“时间戳 计量点 ID”去重就行。但要注意有些点位上报时间不是严格等间隔比如有的采集器每隔 15 分钟上报但偶尔会延迟到 20 分钟才报。所以做清洗之前我会先把原始时序数据重采样到统一的时间网格比如把非整点的数据聚合到最近的 5 分钟或 15 分钟窗口。MyEMS 本身有按小时、按日聚合能耗的接口但 15 分钟级别的高频数据经常需要自己从原始表里处理。2.2 特征构造不只是“过去的负荷”负荷预测模型最容易犯的错误是只把历史负荷丢进去其他什么都不管。实际上影响电力负荷的因素远远不止“昨天这个时候是多少”。我常用的外部特征可以分成三类时间特征、天气特征、业务特征。时间特征包括是否是工作日、是否是节假日、星期几、小时、是否处于冬夏令时切换日等。这里有个容易忽略的点中国的调休制度会让很多模型措手不及比如周六补班和周中放假。如果不加“是否工作日”字段模型很难自动识别这种不规则变化。我会直接把“节假日类型”做成一个分类变量例如正常工作日、周末、法定节假日、调休上班日同时保留“距上一个节假日多少天”这样的连续变量帮助模型理解节假日前后的负荷形态。天气特征对夏季和冬季负荷影响非常明显。空调负荷占比高的商业建筑当天最高温度、前一天的平均温度、湿度、降雨量都会改变用电曲线。最典型的例子是夏天同一座写字楼室外温度 35 度和 28 度的下午高峰负荷可能相差 20% 以上。我在做模型时会把温度做成滞后特征因为建筑物本身有热惯性。当天中午的气温会影响下午两点到三点的空调负荷但不会立竿见影模型需要学习温度变化和负荷响应之间的延迟关系。如果拿不到未来天气的预报值作为输入就只能用历史温度做滞后特征如果能接入气象预报 API就能把未来 24 小时温度预测也加入模型输入进一步提升精度。业务特征需要去看被预测对象的实际用电性质。如果是工厂就要考虑产能、排班、是否在赶订单如果是商业综合体会考虑营业时间。这些信息不一定能实时拿到但至少要作为一个开关变量。比如某园区周末没有生产只在部分楼层开空调那么“是否生产日”就是最高优先级的特征。做完特征之后还要控制特征数量。我见过有人一口气加了 50 个特征LSTM 训练时间成倍增加效果反而下降。刚开始做时我建议先只带上历史负荷、小时、工作日属性、温度四类核心特征跑出一个基线再逐步叠加其他特征观察验证集误差是否真正下降。否则所有特征堆在一起无法判断哪个特征是有用的也会导致模型过拟合。2.3 归一化与训练集/验证集切分LSTM 对输入特征的尺度非常敏感。历史负荷可能动辄几千千瓦小时特征范围在 0 到 23温度值在零下十度到四十度之间。如果不归一化模型训练时梯度更新会被量级大的特征主导量级小的特征几乎不起作用。我常用的是 MinMaxScaler把每个特征缩放到 0 到 1 之间。具体做法是在训练集上计算每个特征的最小值和最大值然后用同一组参数去缩放验证集和测试集千万不能用全量数据去计算归一化参数。否则验证集的信息会被提前“看”到评估结果就不真实了。数据切分也要符合时间序列的特性。很多人做机器学习时习惯用随机抽样切训练集和测试集这种思路在时间序列预测里是大忌。负荷数据具有强时间相关性随机抽样会把时间顺序打乱让模型“偷看”到未来数据测试结果当然好看但一上线就会露馅。我采用的方法是按时间切分前 70% 的数据作为训练集接下来的 10% 作为验证集最后 20% 作为测试集验证集和测试集都必须严格位于训练集之后。切分之后还要把数据组织成 LSTM 需要的样本格式。LSTM 的输入通常是三维张量形状是(样本数, 时间步长, 特征数)。假设我要用过去 7 天每天 96 个点的数据预测未来第 8 天的负荷时间步长就是 7*96672特征数是包括负荷、温度、时间标记等在内的字段数量。这样一个样本的滑动窗口就非常大训练时会比较吃内存。如果预测周期是未来一小时时间步长通常可以缩小到过去 24 小时或 48 小时效果也足够。窗口大小没有绝对标准需要通过实验来确定我从两天到两周都试过。短窗口模型更灵敏能快速跟踪负荷突变但噪声大长窗口能学到更稳定的周期规律但结构更重。对于未来 24 小时预测我最终通常选择历史 7 天作为默认窗口。3. LSTM 模型搭建与训练细节核心环节3.1 网络结构设计从单层到双向的取舍模型结构我建议从简到繁不要第一次就搭一个五六层的大网络。LSTM 层数增加能提高模型表达能力但训练难度和过拟合风险也上去了。我最初在 MyEMS 项目里使用的是单层 LSTM隐藏单元数设为 64后面再接一个全连接输出层。对于中小规模的负荷数据这个结构已经能学到不错的时序特征。单层模型训练速度快上线之后预测一条数据也只需要几毫秒方便做实时预测。如果单层模型验证集误差一直下不来再尝试两层 LSTM隐藏单元数可以设置成 128同时在全连接层之前加入 Dropout 层比例一般设置在 0.2 左右防止过拟合。需要注意LSTM 层的 Dropout 不能加在循环连接内部而是加在层的输出上。Keras 和 PyTorch 都有各自的标准用法需要仔细看文档乱加 Dropout 可能会导致训练不稳定。有些论文里会提到双向 LSTM。双向 LSTM 会同时从正向和反向处理序列。对于自然语言理解因为一句话的完整意思需要结合上下文双向确实好用。但负荷预测是严格的因果关系预测预测未来不能依赖“未来时刻”的数据双向网络会在训练时把中间时刻之后的信息也编码进来这可能造成数据泄露。如果做的是负荷“补全”或“后验分析”双向结构可以考虑如果做实时预测我建议坚持单向 LSTM最多在注意力机制或残差结构上做文章。在 MyEMS 的实际部署场景里我不把整个 LSTM 网络部署得过于复杂。生产环境需要考虑推理稳定性和响应速度尤其是当客户有数十个计量点的时候。模型结构复杂并不一定带来精度提升性价比不高。我的做法是先做一个基线网络跑通整个流程再针对误差大的点位单独调整。3.2 损失函数、优化器与学习率负荷预测是回归问题最常用的损失函数是均方误差和平均绝对误差。均方误差的优点是对大误差惩罚更重能让模型更关注那些偏差很大的点但也会让模型被少量极端值带偏。平均绝对误差更稳定对异常点不敏感但收敛到最优解的速度会慢一些。实际使用中我经常用 HuberLoss它在误差较小时表现为平方误差误差较大时表现为绝对误差相当于两者的结合。如果你是新手直接使用均方误差一般就能跑出不错的结果后面再根据误差分布调整。优化器我习惯用 Adam。Adam 自适应调整每个参数的学习率在大多数情况下不需要手动设计学习率衰减策略。但 Adam 并不意味着完全不用调学习率。如果学习率设置得太高比如 0.01 以上损失函数会在训练初期反复震荡设置得太低比如 0.00001模型可能会卡在很次优的位置训练几百轮还是没进展。我在 95% 准确率这个项目里采用的初始学习率是 0.001训练 60 轮左右时用验证集损失来挑选最佳权重而不是只看最后一轮。PyTorch 里可以用ReduceLROnPlateau在验证损失不再下降时自动降低学习率每次乘以 0.5最低降到 0.00001这样既省心又能提升稳定度。批大小也直接影响训练效果。我通常用 32 或 64。如果单条样本窗口很长、特征很多批大小太大会导致显存溢出太小则会让梯度更新过于频繁训练不稳定。一次训练中我建议把训练过程中的训练损失和验证损失曲线都打印出来看看。如果训练损失一直在下降但验证损失提前回升说明已经开始过拟合此时应该早停或者加强正则化如果两者都在缓慢下降说明模型还在学习可以适当延长训练轮数。3.3 训练过程监控与模型保存不要等到训练完再看结果。我的习惯是在每个 epoch 结束时计算验证集上的 MAPE 和损失并打印出来。如果前 5 个 epoch 验证损失下降很快后边进入平台期这说明大概率已经接近收敛。如果验证损失在训练中反复波动最大可能是学习率偏大或批大小不合适需要先停下来修参数再继续训练。模型训练完成后不能只保存网络权重文件还要把归一化器的参数一并保存下来。我在项目里会保存一个字典文件里面包含特征列名、均值、最小值、最大值、时间步长、预测步长等元数据。这样的话线上预测时可以从同一个字典恢复归一化参数再对输入数据进行相同的变换。很多人上线后模型预测结果偏得离谱查了很久才发现是归一化过程不一致训练时用的是 MinMaxScaler线上服务里却忘了做逆变换。模型格式方面PyTorch 可以用.pt或.pth文件保存。不过我的部署环境里不一定有 PyTorch 依赖所以我会把模型转成 ONNX 格式再在预测服务中加载 ONNX Runtime 推理。这样既能统一管理多个预测点也能减少内存占用。ONNX 的转换过程本身不复杂但要注意把 LSTM 的初始隐藏状态固定下来避免转换后输入输出结构不一致。4. 把模型嵌入 MyEMS 集成流程从训练到线上预测4.1 预测服务与定时任务模型训练本身只是离线部分真正让客户觉得有价值的是把预测能力接进 MyEMS 系统里。我的集成策略是让 MyEMS 保持原来的数据采集和展示核心不变在外面单独部署一个预测服务。这个服务可以是一个 Python 进程也可以是一个 Docker 容器主要承担三种职责加载模型和归一化配置、按调度频率生成预测、将预测结果写回 MyEMS 的数据库。这里涉及到架构选型。为什么不把预测代码直接写死在 MyEMS 后端因为 MyEMS 本身采用 Java 等企业级技术栈开发部署和升级依赖比较重。把 Python 的机器学习环境塞进主服务进程会让系统变得脆弱模型更新时还会牵动整个应用重启。独立预测服务的好处是可以单独开发和训练模型不会干扰能源数据采集的稳定性。同时 Python 生态对数据处理和模型推理的支持也更好。定时任务我用两种方式实现。第一种是在预测服务内部使用类似 APScheduler 的库指定每天凌晨 0 点跑一次未来 24 小时预测或者每个整点跑一次下一小时预测。第二种是通过外部系统的 Cron 或容器调度器触发调用预测服务提供的命令。我更推荐第二种因为这样能把训练任务、预测任务、数据同步任务的优先级分开管理。比如电力市场要求每天上报次日负荷曲线那就需要在当天 18 点前生成结果而企业内部容量控制需要分钟级滚动预测这一类任务更适合单独调度。4.2 API 调用与结果展示预测服务跑起来后需要把预测结果对外暴露。最常用的形式是 REST API。MyEMS 侧可以通过定时任务调用这个 API把返回的 JSON 数据解析后写入能耗预测表。API 请求中需要带上计量点标识和预测时间范围例如某一个楼层的总进线电表 ID预测未来 24 小时的 15 分钟负荷曲线。返回结果应该包含时间戳数组和对应的预测值数组。我通常还会额外返回预测置信区间因为对客户来说知道预测误差范围比只知道一个点更有价值。如果预测值是 1000kW但置信区间是 800 到 1200kW客户在做需量控制时会更谨慎不会把设备负载压得太狠。展示层我是直接复用了 MyEMS 的图表能力把预测曲线和历史负荷曲线放在同一个图表中对比。如果 MyEMS 自带的数据可视化不好扩展可以单独做一个简易的 Web 页面用 ECharts 之类的库画两组折线实际负荷和预测负荷。这样运维人员可以一目了然地看出模型是否跟踪得准。对于偏差较大的时段系统还要支持点击查看该时段对应的外部特征数据比如温度、湿度、是否工作日等方便人工分析原因。4.3 效果评估与准确率复现部署完成不是终点我通常会给系统设计一个回测和线上评估流程。回测是在历史数据上模拟预测记录每一个预测点的预测值和真实值。线上评估是定时抓取最新真实负荷数据和之前生成的预测值对比计算滚动 MAPE。为了复现 95% 准确率需要注意评估的时间窗口要和客户预期一致。同一个模型在春季常温天气下 MAPE 可能只有 3%而在夏季雷雨多发天气下可能超过 6%。我在向客户汇报时会分别给出工作日、周末、节假日、高温日、低温日的评估结果而不是只报一个整体数字。最终客户的验收标准通常以连续一个月的预测误差为基准这样更公平也更贴合实际运行条件。模型上线后我还会做周期性的重训练。建议至少每月重训练一次把新产生的数据纳入训练集。如果客户有明确的季节性变化比如北方地区冬天有集中供暖用电结构发生改变可以把重训练缩短到两周一次。完全静态的模型不可能长期维持高精度因为用电行为、设备效率、生产计划都会慢慢漂移。5. 常见问题与调优实战我踩过的坑5.1 数据泄露看起来很高实际一塌糊涂数据泄露是时间序列预测里最容易暗藏的问题。我第一次给一个园区做模型时验证集 MAPE 只有 2%比后来单独测试低了非常多。查了很久才发现原因我在数据处理时用了全量的归一化也就是用整个数据集的均值和最大值去缩放特征。由于归一化参数包含了测试集的信息模型在训练时实际上拿到了未来数据的统计范围所以验证时显得特别精准。这个问题在热力图和特征重要性分析里都不容易发现需要检查数据处理管线中每一步是不是只用了训练集信息。另一个数据泄露来源是样本构造重叠。假设我用过去 7 天预测未来 1 天然后每隔 1 个小时滑一次窗生成一个新样本。相邻两个样本会有大量重复时间点这本身没什么问题但在划分训练集和验证集时必须按“预测目标时间”来切割不能按样本生成的先后顺序直接切。否则训练集最后一个样本和验证集第一个样本的预测目标可能只差 1 个小时时间相关性让大部分信息重叠模型在验证集上会表现得过于乐观。5.2 模型不收敛或欠拟合先别急着加层遇到 LSTM 模型训练损失一直不降很多人第一反应是“模型太浅了加层”。但在我遇到的实际案例里训练损失不降最常见的原因是学习率不合适、数据没有归一化、或者是输入特征包含了太多非信息性噪声。加层只会让模型更难优化。如果模型收敛了但预测误差很高也就是欠拟合这时候再考虑增强模型表达力。可以尝试调整隐藏单元数从 32 到 128或者把时间窗口从 24 小时扩大到 7 天。还有一个容易被忽视的方向是输出长度。如果模型直接预测未来 24 小时的所有 96 个点这个任务会非常困难。为了降低难度我把预测拆成了两种方式一种是“单步滚动预测”先预测未来 15 分钟再用预测值作为输入预测下一个 15 分钟但这样误差会逐步累积另一种是“序列到序列”用编码器把历史序列编码成一个状态向量解码器再一步步生成未来多个点。第一种实现简单适合 4 到 6 小时的短时预测第二种误差控制得更好适合 24 小时预测但实现复杂一些。我在最终项目中采用的是多任务输出方式也就是让 LSTM 输出一个长度为未来预测点数量的向量同时用损失函数对未来的近端时段和远端时段分别赋予不同权重。近端的预测误差往往会更小远端会偏大所以不能期望所有时段都保持同样高的精度。5.3 效果达标的边界与模型维护建议最后说点现实的话95% 准确率不会在所有数据源上都复现。单体建筑、变化剧烈的工业负荷、受天气影响很大的区域电网模型的表现会有很大差别。如果某个客户的负荷完全没有规律比如一家小作坊里几台设备随机启停任何模型都很难做到很高的预测精度。这时候比较好的做法不是继续调模型而是跟客户沟通清楚预测能力边界高频随机波动无法被准确预测但整体趋势和峰谷时段仍然有参考价值。模型上线后建议建立一套简单的监控页面展示每天每条预测曲线的 MAPE。如果连续一周某一点位的误差超过 10%就需要检查是不是设备更换、产能变化或数据库字段变动导致特征理解失效。类似 MyEMS 这类能源管理系统一旦接入 AI 模型实际上形成了一条“数据采集-清洗-训练-预测-反馈-再训练”的闭环长期运行下来模型不是越用越差而是越用越贴近现场。我在实际项目里还有一个习惯每次重训练模型后都把旧模型的预测结果和新模型的结果做一段时间的并行对比等新模型的误差稳定低于旧模型时再切换。这个做法虽然多占一点计算资源但在生产环境里能避免很多因为训练噪声、异常数据导致模型突然变差的麻烦。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进