ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

TensorFlow LSTM短期电力负荷预测实践:从数据清洗到模型上线

TensorFlow LSTM短期电力负荷预测实践:从数据清洗到模型上线 简介基于TensorFlow的LSTM循环神经网络短期电力负荷预测PDF是一份面向电力系统、智能电网与深度学习从业者的技术文档聚焦电力负荷高精度预测这一核心问题。文档系统讲解LSTM循环神经网络的结构原理包括输入门、输出门与遗忘门机制并结合TensorFlow框架从数据预处理、特征选取、数据迭代与参数更新到模型训练与预测给出完整实验思路同时涉及电力系统运行经济化、智能电网与人工智能等相关背景有助于读者建立从理论到实践的认识。内容基于某地区发电厂实际负荷数据设计实验结论显示该方法明显优于传统机器学习算法且随数据量增大表现出良好鲁棒性。整个压缩包包含1个PDF文件大小2.27MB排版清晰适合作为机器学习、时间序列预测及电力负荷预测领域的学习参考或专业指导材料。已有794人学习浏览适合电力行业从业者、高校相关专业学生及对深度学习预测感兴趣的技术人员研读。1. 短期电力负荷预测为什么卡在“动手跑通”这一步凌晨三点配电房的SCADA系统回传昨天每五分钟一条的负荷曲线你要在早上八点之前给出未来24小时的预测。电力负荷这东西白天跟着生产线涨晚上跟着商场和空调走周末又踩出另一条节奏。短期电力负荷预测要解决的就是这种“明天每个小时大概多少负荷”的问题而LSTM循环神经网络天生适合吃这种带记忆的时间序列——它靠着三个门把过去几天甚至几周的负荷形态记在内部状态里再用TensorFlow那一套成熟的训练和部署体系推下去。你手头这份《基于TensorFlow的LSTM循环神经网络短期电力负荷预测》的文档第一遍读下来理论往往很顺直到照着配环境、造数据集、调模型才发现每个环节都有隐藏坑。这篇笔记不讲理论推导按数据清洗、窗口构造、TensorFlow建LSTM、训练评估、上线排查这条线路走一遍让做毕业设计、做能源管理平台的新手能直接复现也能让熟手对照参数边界。2. 数据准备把历史负荷整理成LSTM能吃的小批量2.1 先搞清楚数据长什么样负荷序列的三个基本属性LSTM再聪明也没法替你决定“以什么频率喂数据”。拿到一份电力公司导出的负荷数据集第一件事不是建模而是确认三件事时间粒度、时间跨度、有没有外部特征。常见做法是看文件头两列一般是datetime和loadload 单位可能是 MW 或者 kW。粒度又分15分钟、30分钟、60分钟三种论文里常说的“短期负荷预测”很多都落脚在小时级因为电力市场的结算和调度计划基本按小时排。为什么粒度重要LSTM 的 lookback 窗口是按“几个时间点”决定的不是按“几个小时”决定的。如果原始数据是15分钟一条一天就有96个点如果是60分钟一条一天只有24个点。用同样的 lookback24前者只看了6小时后者看了整整一天相差很远。所以第一步就是把粒度定下来比如统一重采样到小时宁可丢掉一些高频抖动也别让粒度忽高忽低。重采样代码很简单df.resample(h).mean()但要注意时区。国内数据集一般直接给北京时间没有时区问题如果是国外数据集必须先把 UTC 换算成当地时间再重采样否则白天高峰会错位一个时区模型会学到一条鬼畜的对应关系。2.2 清洗和补齐缺失值、突变尖峰、限电日不能一锅燉负荷数据不是实验室里产出的干净序列。我拿到过的实际数据里有凌晨两点变成负数的有连续120个缺失值躺在那里的还有因线路检修突然跌到接近零的这些都对训练不友好。缺失值数量少时线性插值是最稳的选择缺失段长时线性插值会把本来有昼夜峰谷的曲线拉成一条直线形成“伪历史”。我的习惯是短于6个时间点的缺口直接插长缺口只补周围一小段并打上标记不要为了凑连续样本而创造一段根本不存在的负荷形态。import pandas as pd import numpy as np df[time] pd.to_datetime(df[time]) df df.set_index(time).sort_index() # 先做物理解析负荷不可能为负超上限按缺失处理 df.loc[(df[load] 0) | (df[load] 50000), load] np.nan # 短缺口用时间索引线性插值limit6 保证长缺口不被硬填 df[load] df[load].interpolate(methodtime, limit6, limit_directionboth)这里methodtime表示按时间间隔比例插值而不是把两个点机械地拉直线。limit6的含义是只允许对连续缺失不超过6个点的地方补值超出部分保持缺失。等后面做窗口时直接把含缺失值的样本丢掉即可。至于突变尖峰先别急着修很多尖峰是真实的空调集中启动或工业负荷投切修掉之后误差会非常平均反而掩盖了模型处理异常点的能力。只有那些物理上不可能的跳变才置为空值。2.3 窗口化从一维序列到带“记忆”的三维样本LSTM 的输入要求是三维(样本数, lookback, 特征数)。一维负荷序列想变成三维得先制造“窗口”。所谓窗口就是拿前面连续24个点预测下一点。这个函数几乎是必备工具我通常直接写成工具函数放进项目里。import numpy as np def make_windows(data, lookback24, horizon1): X, y [], [] for i in range(len(data) - lookback - horizon 1): X.append(data[i : i lookback]) y.append(data[i lookback : i lookback horizon]) return np.array(X), np.array(y) # 假设 data 是清洗、归一化后的一维 numpy 数组 lookback 24 # 用过去24小时预测 horizon 1 # 预测下一小时 X, y make_windows(data, lookbacklookback, horizonhorizon) X X.reshape(X.shape[0], X.shape[1], 1) print(X.shape, y.shape) # 期望输出类似 (N, 24, 1) (N, 1)窗口越大样本数越少训练数据越“稀疏”。这里horizon1是单步预测也就是已知过去24小时预测下1小时。如果做“明天24小时预测”很少有人只用一个 LSTM 直接输出24个数常见做法要么是用训练好的单步模型滚动预测24次要么构造horizon24让模型直接回归24维向量。前者更简单后者更快后面第6章再展开。构造窗口时有个细节经常被忽略如果用滑动步长1相邻窗口的重叠极大训练集里的样本高度相关会诱发过拟合。如果你的数据集很长可以步长设为lookback // 2甚至8让窗口少重叠。注意测试集必须保持最后一个窗口覆盖到当前最新历史为止否则预测时少拿一段最新数据。2.4 归一化必须做但不要一步到位全量拟合负荷值动辄几千上万一个 LSTM 的 tanh 激活函数只适合处理 [-1,1] 附近的输入不归一化直接训练前期梯度会震荡到让人怀疑代码写错。归一化用 MinMaxScaler 最省事但顺序错了就是“数据泄漏”先对全量数据fit再切训练集和测试集等于让模型在训练阶段偷看过测试集的取值范围验证时好看上线后立刻翻车。正确做法是先按时间切分再用训练段fit。from sklearn.preprocessing import MinMaxScaler scaler MinMaxScaler(feature_range(0, 1)) total_len len(df) train_end int(total_len * 0.8) val_end int(total_len * 0.9) # 只用训练段拟合 scaler train_raw df[load].iloc[:train_end].values.reshape(-1, 1) scaler.fit(train_raw) # 全量数据统一 transform但 fit 信息只来自训练段 scaled_all scaler.transform(df[load].values.reshape(-1, 1)) df[load_scaled] scaled_all train_data df[load_scaled].iloc[:train_end].values val_data df[load_scaled].iloc[train_end:val_end].values test_data df[load_scaled].iloc[val_end:].values注意scaler.fit(train_raw)只做一次之后的验证集和测试集都是同一个 scaler 的transform不做二次拟合。单位负荷分布季节性很强冬天和夏天负荷基准不同训练段 fit 的 [min, max] 在测试段可能被超出范围的值冲破MinMaxScaler 默认会把超出部分压到0或1边界这其实是个信息损失点。所以更稳的替代方案是用StandardScaler做标准化容忍极端值但收敛速度略慢。对我来说做短期负荷预测用 MinMaxScaler 居多因为负荷波动范围相对确定超限不常见。3. 用TensorFlow搭LSTM从单层到堆叠的选型与参数3.1 为什么选LSTM而不是普通RNN也不急着上Transformer很多人问现在 Transformer 这么火直接用注意力结构不香吗这要分清场景。电力负荷预测里数据规模通常只有几千到几十万条Transformer 的全局注意力在这种规模下学不到比 LSTM 更强的时序依赖反而更容易过拟合。普通RNN则存在梯度消失问题预测24小时这种中长依赖时记忆会被后段状态冲淡。LSTM循环神经网络用遗忘门、输入门、输出门把历史信息保留在细胞状态里碰到负荷这样有强昼夜周期、有周末突变、还受温度影响的序列它在同样数据量下训练稳定超参数也好调。这也是为什么你搜索“tensorflow与pytorch的流行趋势”大量新论文都在 PyTorch 里演示 LSTM但生产环境里 TensorFlow 的 Keras 接口依旧有大量存量工程上并不落后。3.2 最小可跑的 LSTM 模型代码先出结果再谈调参搭建模型这块我强烈建议先跑一个只有单层 LSTM 的最小模型别一上来就堆三层。先确保数据管道、损失函数、预测输出这三个环节能对得上模型能收敛再考虑如何加深度。import tensorflow as tf from tensorflow.keras.models import Sequential from tensorflow.keras.layers import LSTM, Dense model Sequential([ LSTM(units64, activationtanh, input_shape(X_train.shape[1], X_train.shape[2])), Dense(1) ]) model.compile(optimizeradam, lossmse) model.summary()这段代码里有三个关键点。units64不是神经元数量而是 LSTM 输出空间的维度也就是隐藏状态的大小它决定了模型记忆容量。input_shape必须写(lookback, features)千万别把样本数带进去。Dense(1)输出一个标量对应下一个时间点的负荷值。lossmse对负荷序列很适用因为它对大幅误差惩罚更重异常尖峰会被压住。3.3 堆叠 LSTM 和 Dropout什么时候需要第二层单层模型如果验证集 MAE 一直下不去或者曲线整体滞后一拍再考虑堆第二层。加第二层的理由是希望模型先在第一层提取局部模式再在第二层提取长周期依赖。但第二层不是白加的计算量和过拟合风险都会增加。from tensorflow.keras.layers import Dropout model Sequential([ LSTM(units64, return_sequencesTrue, activationtanh, input_shape(X_train.shape[1], X_train.shape[2])), Dropout(0.2), LSTM(units32, activationtanh), Dense(units16, activationrelu), Dense(1) ])注意第一层return_sequencesTrue这样它输出的不再是最后一个时间步的隐藏状态而是每一步的隐藏状态序列第二层 LSTM 才能继续处理。Dropout 加在两层之间概率 0.2 起步太高会让训练落到欠拟合。还有一个 LSTM 特有的训练现象它在 CPU 和 GPU 上的浮点计算顺序不同同样的数据、同样的模型结果会有微小差异后面避坑章会说。3.4 lookback 到底设多少24小时、168小时还是两组一起用这是参数里最玄学的一个。电力负荷有24小时日周期也有7天工作日/周末周期所以 lookback24 是最低要求lookback16824×7能覆盖完整周周期。很多论文会把24和168两个窗口拼接成双通道输入工程上我见过更朴实的做法先跑 lookback24 和 lookback48 做对比哪个在验证集上更稳就用哪个。因为168维输入会让样本长度一下子变长小数据集在窗口第150步时已经快接近起点特征早已被遗忘门截断。如果数据量足够把lookback当作超参搜索搜索范围 [24, 48, 168]用验证集 MAE 选择。不要直接拿测试集试参数否则相当于每天翻着答案考试。4. 训练和评估别只盯着训练集损失把预测结果拉回到真实尺度4.1 训练集、验证集、测试集按时间切不随机切LSTM的时间依赖决定了样本顺序就是信息本身。如果把train_test_split默认的随机切分用在负荷数据上训练集里会出现未来时间段的窗口验证集里又会混进历史相邻的样本模型在训练时已经见过验证集“附近”的负荷曲线评估结果虚假乐观。更麻烦的是预测任务就是想用过去推未来随机切分违背了这个场景。train_len int(total_len * 0.7) val_len int(total_len * 0.15) test_len total_len - train_len - val_len X_train_raw X[:train_len] y_train_raw y[:train_len] X_val_raw X[train_len:train_lenval_len] y_val_raw y[train_len:train_lenval_len] X_test_raw X[train_lenval_len:] y_test_raw y[train_lenval_len:] # 让最后一维与模型输入对齐 X_train X_train_raw.reshape((X_train_raw.shape[0], X_train_raw.shape[1], 1)) X_val X_val_raw.reshape((X_val_raw.shape[0], X_val_raw.shape[1], 1)) X_test X_test_raw.reshape((X_test_raw.shape[0], X_test_raw.shape[1], 1))上一节已经提过窗口在整个数据上生成后再切片顺序依然是时间序。这么做虽然窗口有重叠但只要按时间边界切验证集和测试集至少晚于训练集出现就没有未来信息泄漏。我一般会把训练集放70%、验证集15%、测试集15%验证集用来提前停止测试集只用来做最终打分。4.2 训练循环的常用设置EarlyStopping 是标配shuffle 要看情况训练循环看起来简单配置不对就白跑。有些项目跑了几百个 epoch训练损失还在缓慢下降验证集反而上涨这是典型过拟合。EarlyStopping 能帮你自动停在最佳位置。from tensorflow.keras.callbacks import EarlyStopping, ReduceLROnPlateau early_stop EarlyStopping( monitorval_loss, patience10, restore_best_weightsTrue ) reduce_lr ReduceLROnPlateau( monitorval_loss, factor0.5, patience5, min_lr1e-5 ) history model.fit( X_train, y_train, validation_data(X_val, y_val), epochs100, batch_size64, callbacks[early_stop, reduce_lr], shuffleFalse )这里有个容易忽略的点shuffleFalse。RNN/LSTM 时间序列训练里部分框架默认在每个 epoch 开始前打乱样本但电力负荷窗口之间存在重叠打乱后相邻窗口会被拆到不同 batch虽然梯度更新还在但模型看到的“局部时间结构”会乱掉。保守做法是不打乱让每个 batch 里的窗口保持时间连续。batch_size64看显卡而定数据集小就用32数据集大可用128。ReduceLROnPlateau是我每次必配的后悔药验证损失停在平台期时学习率自动减半常常能让模型再降一截。4.3 评估指标MAE、RMSE、MAPE三者怎么选预测值在模型里是归一化后的要计算真实误差必须先经过 scaler 反变换回原始负荷值。这一步别漏否则你会得到一堆零点几的“看起来很完美”的 MAE。from sklearn.metrics import mean_absolute_error, mean_squared_error y_pred model.predict(X_test, verbose0) # 把预测值和真实值都拉回原始负荷单位 y_true_inv scaler.inverse_transform(y_test.reshape(-1, 1)).flatten() y_pred_inv scaler.inverse_transform(y_pred.reshape(-1, 1)).flatten() mae mean_absolute_error(y_true_inv, y_pred_inv) rmse np.sqrt(mean_squared_error(y_true_inv, y_pred_inv)) mape np.mean(np.abs((y_true_inv - y_pred_inv) / y_true_inv)) * 100 print(fMAE: {mae:.2f} MW, RMSE: {rmse:.2f} MW, MAPE: {mape:.2f}%)注意y_test的 shape 分两种情况单步预测时是(N, 1)直接 reshape如果验证horizon24y_test是(N, 24)反变换时要对每一列单独处理不能整体 reshape否则会破坏时间对应关系。三个指标里MAE 最直观RMSE 对大误差敏感MAPE 适合不同负荷级别的方案对比但它在午夜低负荷时段容易爆出无穷大因为分母接近0。如果你发现 MAPE 高得离谱先看是不是有凌晨低负荷样本而不是模型坏了。4.4 画图检查残差预测和真实曲线错位能看出很多问题数值指标能说明好坏但看不到模型错在哪里。负荷预测常见的失败模式是预测曲线比真实曲线滞后一小时简单 ARIMA 模型容易犯这种错LSTM 也会。这时要画一张尾部测试段的对比图把真实和预测画在同一张坐标里。import matplotlib.pyplot as plt plt.figure(figsize(12, 5)) plt.plot(y_true_inv, labelactual, linewidth1) plt.plot(y_pred_inv, labelpred, linewidth1, alpha0.8) plt.legend() plt.grid(alpha0.3) plt.show()如果看到预测比真实晚了一个相位多半是 lookback 窗口不够长或者输入里缺少“当前时间”这类的周期编码。还有一种常见问题是模型把昨天的负荷复制到今天画出来整体沿 45 度线偏移那是单步预测滚动多步时的递归误差第四章1的4.2节会再展开。5. 短期负荷预测里的常见坑现象、原因和排查路子5.1 MinMaxScaler 在全量数据上 fit验证集高考试谎现象训练集 MAE 漂亮测试集 MAE 暴涨并且预测曲线整体比真实值矮一截。原因习惯性地在写代码时先scaler MinMaxScaler().fit(df[load])再切数据。测试集的最小值和最大值已经被 scaler 记住模型在训练阶段就“看到”了测试集的分布范围推理时一旦真实负荷超出训练集范围scaler 直接把超限部分压缩到边界等于测试误差被人为掩盖。解决严格按照“先切训练/验证/测试再只对训练段 fit scaler最后整体 transform”的顺序。推理上线时还用同一个 scaler 对最新历史数据做 transform不能重新 fit 最新数据。5.2 数据随机洗牌模型把“未来”当成历史学会了现象验证损失一路下降但模型在部署后对真实最新数据产生的误差明显高于验证误差。原因有些人习惯套用图像分类的代码train_test_split(X, y, test_size0.2, random_state42)默认 shuffle时间序列被切得前后倒置测试集里出现了训练集未来一段的负荷模型学到的不再是时序关系而是对临近窗口的“记忆”。解决绝不随机切分。按时间比例切片或者直接用TimeSeriesSplit做交叉验证。网格搜索超参时也要保持时间顺序宁可用滚动窗口重复训练也不要贪随机切分的便利。5.3 端午、春节、限电这类特殊日让预测突然烂掉现象平日误差在 3% 以内遇到法定节假日前后误差冲到 10%而且模型不是偏高就是偏低没有规律。原因负荷曲线里春节、国庆这类长假和一整周上班的形态完全不同模型训练样本里这种特殊日占比太少学不出独立模式。再加限电、错峰生产等操作负荷会被人为压低模型按历史规律预测当然翻车。解决不要硬扛把日期特征显式加进输入。每个样本给出其对应预测日的“是否工作日”“是否节假日”“距上次节假日第几天”用(lookback, features)里的第二维拼上这些外部变量。节假日列表要按年份维护不能只用周末判断。如果某年春节只有一个样本不必指望模型从数据里学会干脆对节假日样本单独标注并加大惩罚权重。5.4 模型预测结果忽上忽下同一份代码跑两次不一样现象用相同数据和代码昨天跑 MAE 是 50今天变成 57换台机器又是 52被质疑实验不严谨。原因LSTM 权重随机初始化加上训练时的数据顺序随机、GPU 并行浮点计算顺序不稳定结果天然有波动。这不是代码 bug但会让毕业论文和投标方案失去说服力。解决固定随机种子包括tf.random.set_seed(42)、np.random.seed(42)、random.seed(42)。但固定种子只是表面稳定真正可信的做法是同一配置跑5个种子记录 MAE 的均值和标准差用区间汇报结果。如果波动过大检查学习率是否太高或者训练样本太少。5.5 模型中看不中用模型轮训太多推理时忘加载最新权重现象模型在历史测试集上表现良好但时间往前走了一周新数据来了预测依旧准直到某天凌晨预测整天负荷全部错位。原因负荷分布有季节性漂移夏天和冬天的模式差异很大模型只学过训练集段的分布长期不重训就落后于趋势变化。解决定期离线重训并保留最近一段时间做验证。常见做法是每天早上拉前一天的真实负荷追加到训练集重新训练一轮。TensorFlow 里保存和加载用model.save()和keras.models.load_model()但注意重训后必须重新用原来的 scaler 工具类处理新数据scaled 的fit范围也要跟着训练集滑动更新。6. 让模型真正上线的三个技巧多步预测前沿、模型保存和伪在线回测最后一处值得下功夫的地方是把单步预测扩展到未来24小时。一种最省事的做法是递归预测把预测出的下一点重新拼到输入窗口尾部再预测下下点。注意这样误差会像滚雪球一样累积所以我通常会在模型训练时适当引入噪声或者采用horizon24的直接多步回归把最后一层改成Dense(24)。这样模型一次输出未来24小时误差不再逐点递归堆积代价是训练样本变少容易过拟合需要配合早停和多组种子集成。模型保存上我用 Keras SavedModel 格式存模型结构和权重脚本里再单独存一份 scaler 的最大最小值和lookback窗口长度。真正上线时这两个文件缺一个都会让推理程序黑匣子化——只存二进制模型权重几周之后自己都不知道输入该是什么 shape。伪在线回测是个容易被跳过但又极其重要的验证方法把历史数据按时间顺序切成若干个“新趋势”段每段开始时只用之前数据进行训练然后对这段做多步预测记录误差。这样模拟真实上线流程而不是一次性把测试集跑完。我现在每次上线前至少会保留最近两周数据做一次伪在线回测看模型在“未曾见过的一周”里误差是否还在可接受范围再决定要不要更新训练集。这步踩得坑多了反而成了最省心的保险。希望帮到你。本文还有配套的精品资源点击获取
返回列表