ARTICLE DETAIL

资讯详情

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

基于LSTM的短期电力负荷预测:从门控原理到工程实践

基于LSTM的短期电力负荷预测:从门控原理到工程实践 简介一份基于LSTM循环神经网络的短期电力负荷预测论文PDF面向电力系统调度、负荷预测研究人员及深度学习初学者。内容围绕长短期记忆单元与循环神经网络展开系统阐述LSTM输入门、输出门、遗忘门机制及其在时序负荷建模中的应用并对比统计学方法与机器学习方法给出不同历史窗口和网络架构下的预测性能验证。PDF共1个文件约1.45MB便于直接阅读与打印。目前已有479人浏览学习。读者可从中学到完整的研究思路、数学推导、模型构建流程及实际负荷数据上的实验对比适用于撰写相关论文、开展负荷预测项目或入门时序预测模型。整体内容聚焦电力负荷精准预测这一实际问题兼具理论深度与工程参考价值对提升预测准确性和稳定性具有直接帮助。1. 短期电力负荷预测为什么LSTM能比SVM准4倍电力负荷预测这个活儿干过的人都知道有多磨人。调度要拿预测结果排机组组合、定发电计划、组织现货交易你报出去的数差几个百分点后面就是实打实的真金白银。这篇《基于LSTM循环神经网络的短期电力负荷预测》是《电力工程技术》2021年第1期的论文作者来自南瑞集团。论文里最有说服力的不是模型多花哨而是测试集上的硬指标LSTM的MAPE是2.14%而同期对比的SVM是8.47%KNN是6.77%。也就是说在2003到2018年的美国德州ERCOT真实负荷数据上LSTM的预测误差只有SVM的四分之一左右。这篇论文的核心贡献是把负荷预测拆成了两维来看横向上识别预测日当天负荷随时刻的变化规律纵向上识别历史日期窗口内同一时刻的负荷规律再叠加气温、日期类型这些外部因素全部喂进LSTM网络。方法支持灵活定义历史窗口期、灵活添加负荷影响因素这正好解决了传统统计方法和普通机器学习方法顾此失彼的痛点。适合谁看正在做负荷预测课题的学生、刚接触电力时间序列预测的算法工程师以及想把深度学习方法落到电力场景的从业者。这篇论文给全了实验设计、特征清单和调参路径照着复现一遍比自己从零瞎试省一个月时间。2. 原理先行普通RNN的梯度消失和LSTM的三个门控2.1 普通RNN为什么搞不定长序列负荷数据RNN的核心思想是让隐藏层神经元通过自链接形成循环把上一时刻的隐藏状态传到当前时刻。论文里给出的计算方式是隐藏状态 (h_tf(W_{xh}x_tW_{hh}h_{t-1}b_h))输出 (y_tg(W_{yh}h_tb_y))。其中 (x_t) 是t时刻输入(h_{t-1}) 是上一时刻隐藏状态(W_{xh})、(W_{hh})、(W_{yh}) 分别是输入、隐藏和输出的权重矩阵。这个结构的好处是能处理变长时间序列坏处是训练时用BPTT时间反向传播算法误差沿时间维度从后往前传连乘一堆小于1的梯度值很快梯度就趋近于零了——这就是业内常说的梯度消失。梯度消失的直接后果是RNN学不到长距离的时序依赖。用负荷数据举例今天上午10点的负荷可能和前三天同一时刻的负荷、上周同一天的负荷甚至一个月前的气温趋势都有关系。普通RNN的记忆撑不了那么远训练几十步之后早期信息基本被冲掉了。另一个常见问题是梯度爆炸梯度值连乘大于1的数会指数级放大训练loss直接飞到NaN。处理梯度爆炸可以加梯度裁剪但梯度消失才是RNN在时间序列预测上表现不稳定的根因。2.2 LSTM的门控机制如何解决长距离记忆问题LSTM是对普通RNN神经元的替换在隐藏层神经元里加了记忆单元并引入遗忘门、输入门、输出门三个门控单元来控制记忆单元的读写。论文里的公式拆开看更直观遗忘门 (f_t\sigma(W_f[h_{t-1},x_t]b_f))决定从记忆单元里删除哪些信息输入门包含两部分(i_t\sigma(W_i[h_{t-1},x_t]b_i)) 决定哪些新信息要写入同时用 (\tilde{C}t\tanh(W_c[h{t-1},x_t]b_c)) 生成候选记忆单元记忆单元更新是 (C_tf_t \odot C_{t-1}i_t \odot \tilde{C}t)用的是哈达玛积逐元素乘法输出门 (o_t\sigma(W_o[h{t-1},x_t]b_o))最终隐藏状态 (h_to_t \odot \tanh(C_t))。关键词在这里遗忘门和输入门共同决定记忆单元怎么演化梯度在记忆单元的传递路径上有一条直通的加性通道梯度消失被从结构上规避了。正是因为这一点LSTM能在一段很长的历史时间范围内辨识负荷内在变化规律也能学习气温和工作日这些因素对负荷的非线性影响。选择LSTM而不是GRU或Transformer论文的逻辑也说得通GRU虽然参数更少但门控结构简化后对长周期负荷的建模能力不如LSTM充分Transformer在2017年之后才火起来2021年这篇论文的场景里LSTM在中等规模时间序列上的稳定性更有说服力。实际做项目我也会先用LSTM打底跑通了再对比GRU。2.3 从输入构造角度看LSTM模型的横向与纵向论文里有个设计值得单独拎出来讲模型输入由历史负荷和负荷影响因素共同构成第t时刻的输入是 (input_t{L_{t,d-1},L_{t,d-2},…,L_{t,d-w};F_{t,d}})。历史负荷部分取的是预测日前w天同一时刻的负荷值这是纵向维度让模型看到同一时刻在多天内的变化趋势(F_{t,d}) 包含天气信息、0-1变量的工作日标识、特殊事件标识等这是横向维度让模型理解当天这个时刻的外部条件。两部分拼在一起作为LSTM每个时间步的输入特征。我复现类似项目时发现这个设计对预测精度的贡献比调网络结构还大。原因很简单短期负荷预测里同一时刻的历史负荷本身就是最强的预测因子外部因素更多是修正作用。把纵向历史负荷和横向影响因素拼成特征向量再让LSTM去学两者之间的交互关系比单独用其中任何一种都扎实。后面实验部分也证明即使隐藏层只有一个、每层只有5个神经元MAPE也能做到3.9%这很大程度上归功于输入特征的结构设计。3. 复现论文实验设定数据划分、特征工程与评价指标3.1 数据源与训练集、验证集、测试集的切分逻辑论文的实验数据来自美国德州可靠性委员会ERCOT控制区域2003年到2018年的每小时历史系统负荷数据参考文献里给了公开下载地址。数据切分方式非常规范2003至2016年共14年数据作训练集2017年全年作验证集2018年全年作测试集。验证集用来确定最优训练回合数和最佳网络结构测试集只用来评估最终模型效果绝不参与调参。这种做法我强烈建议照抄。很多入门项目把数据随机打乱再切分这在时间序列预测里是错的——负荷数据有强时间相关性随机打乱等于把未来信息泄露给训练集验证集上看起来表现很好一到线上预测就崩。按时间顺序切分训练集永远在验证集前面验证集永远在测试集前面才能模拟真实的预测场景。另外注意ERCOT的数据粒度是每小时而论文的模型设计里提过当采样间隔为15分钟时T96如果要用更细粒度的数据输入向量长度和LSTM时间步数都要对应调整。3.2 负荷影响因素清单这11个特征是怎么选的论文里表1列出了完整的负荷影响因素清单这是能直接抄作业的部分标识影响因素说明temperature气温当前时刻温度值year年对应年份month月份1~12月day_of_month日/月当月第几日day_of_week周几当前周几0~6hour时刻当前时刻0~23is_business是否工作日0为非工作日1为工作日day_of_year第几天/年当年第几天1~365per_hour_load历史窗口期内同一时刻负荷纵向历史特征per_max_load历史窗口期内每天最大负荷描述窗口内负荷水平per_min_load历史窗口期内每天最小负荷描述窗口内负荷水平这些特征分三类时间标识年、月、日、周几、时刻、当年第几天帮LSTM建立周期性概念气象与日期类型气温、是否工作日体现外部因素对负荷的影响历史统计量窗口内同一时刻负荷、每日最大最小负荷把窗口内的负荷形态用紧凑的方式表达出来。第t时刻的输入向量就是这些特征向量化后拼接的结果最后用最小-最大归一化把每个元素压到[0,1]区间。3.3 评价指标怎么算MAE、RMSE、APE与MAPE论文用四种指标评价模型公式都很基础但值得写清楚。MAE平均绝对误差是 (e_{MAE}\frac{1}{N}\sum_{i1}^{N}|L_i-\hat{L_i}|)衡量预测值与真实值的平均绝对偏差RMSE均方根误差是 (e_{RMSE}\sqrt{\frac{1}{N}\sum_{i1}^{N}(L_i-\hat{L_i})^2})对大误差更敏感APE绝对百分比误差是 (e_{APE}\frac{|L_i-\hat{L_i}|}{L_i}\times100%)反映单个样本点的相对误差MAPE是全部样本APE的均值论文里用eMAPE表示这是跨模型对比的主指标。我计算MAPE时有个小习惯如果真实负荷序列里存在接近零的值APE会变得非常大甚至溢出。电力负荷一般不会等于零但如果做的是分布式光伏或某些净负荷数据凌晨时段可能出现极小值。这时要在代码里加一个下限保护把分母 (L_i) 限制在某个正数如0.01以下否则一个异常点就能毁掉整个MAPE。论文里MAPE最低做到2.14%MAE为41.22MWRMSE为59.29MW三个指标一起看在同等量级下一致性较好说明模型不是靠牺牲某类误差换来的表面低分。4. 模型搭建与训练从数据预处理到最优网络结构搜索4.1 数据预处理两步走向量化与标准化神经网络基于线性代数做计算不能直接在原始表格数据上训练。数据预处理第一步是数据向量化把历史负荷 (L_{t,d-w}) 与负荷影响因素 (F_{t,d}) 拼接成一个向量作为LSTM单个时间步的输入。拼接顺序影响不大但要在训练和预测时保持完全一致否则模型学到的特征分布对不上。第二步是标准化论文采用最小-最大归一化方法公式是 (X_{norm}\frac{X-X_{min}}{X_{max}-X_{min}})把向量内每个元素归一化到[0,1]区间。这里有个细节新手容易忽略归一化的最大值和最小值必须先基于训练集计算并保存再用同一组 (X_{min})、(X_{max}) 去变换验证集和测试集数据。如果对全部数据统一算归一化参数相当于验证集和测试集的信息提前泄露给了训练过程验证出来的最优回合数和网络结构会偏乐观。我一般会把归一化器保存为pickle或json文件推理时加载同一个归一化器来反标准化预测结果这样训练和线上预测的口径才能对齐。4.2 模型训练BPTT、MSE损失与最优回合数论文的模型训练采用BPTT算法训练目标是调整网络参数使输出尽可能接近真实值损失函数选用MSE(L_{a,b}\frac{1}{N}\sum_{i1}^{N}(L_i-\hat{L_i})^2)。训练流程是初始化网络参数、输入训练数据计算输出、计算预测值和实际值之间的损失、按损失函数对参数在层级和时间两个方向上求梯度、根据梯度调整参数循环往复一个回合epoch。回合数过少导致欠拟合回合数过多导致过拟合所以论文里用验证集在每个回合结束后评估模型选择验证集上MAPE最低的回合数作为最优值。我复现这个流程时用的PyTorch实现大致是这样的结构import torch import torch.nn as nn class LSTMPredictor(nn.Module): def __init__(self, input_size, hidden_size, num_layers, output_size1): super().__init__() self.lstm nn.LSTM(input_size, hidden_size, num_layers, batch_firstTrue) self.fc nn.Linear(hidden_size, output_size) def forward(self, x): # x shape: (batch_size, seq_len, input_size) out, _ self.lstm(x) # 取最后一个时间步的隐藏状态映射到预测值 out self.fc(out[:, -1, :]) return out这段代码里input_size对应特征向量的维度也就是历史负荷加影响因素拼接后的长度hidden_size是LSTM隐藏单元数量num_layers是隐藏层层数batch_firstTrue让输入维度按批大小在前排列直观一些。训练时对每个回合计算MSE损失用优化器如Adam反向传播更新权重。论文的损失函数用的是MSE这个选择是有讲究的MSE对大误差的惩罚比MAE更强会让模型更积极地压低离群点误差但代价是对异常值敏感。如果数据里噪声大可以换成Huber Loss。4.3 枚举法调网络结构从表2里能读出什么论文用枚举法确定网络结构方法很朴素但有效固定历史日期窗口w为7天隐藏层数依次设为1、2、3层每层神经元数量从5到40按间隔5共8个级别逐一训练并用2017年验证集评估。表2的数据值得细看隐藏单元数1层eMAPE/%1层最优回合2层eMAPE/%2层最优回合3层eMAPE/%3层最优回合54.605004.751724.59180104.72384.99574.5865154.74534.77384.7448204.94404.72424.6555254.79304.71355.1420304.99245.11204.6552354.80354.83165.0020404.80164.75164.8739三个结论层数增加会拉低最优回合数说明更深的网络收敛更快但也更容易过拟合每层5个神经元的极简结构在单层和三层都表现不错说明这个数据集上模型容量不是瓶颈特征质量才是w7固定时三层各10个神经元的4.58%最优。但如果把历史窗口w放开单层5个神经元在w23天时MAPE能做到3.9%比固定w7时所有结构都好。这引出一个反直觉经验调网络结构不如调历史窗口有效参数不必一味堆大。4.4 历史窗口w的敏感性论文里那条关键的曲线图论文图6给出了不同网络结构下eMAPE随w从1到60天变化的曲线三个发现很有价值。第一w在7到30天范围内三种网络结构的MAPE都稳定在较低区间这个区间是工程上的安全操作区。第二w继续增大到30天以上MAPE没有明显下降趋势反而波动变大说明太久远的负荷数据对预测当日负荷帮助有限甚至引入噪声。第三模型越简单对w越敏感单层5个神经元结构在w较大时MAPE变化剧烈而三层结构相对平稳。我自己做多个数据集后的经验是w的取值应该跟负荷的周期性对齐。如果数据有强周周期工作日和周末差异大w取7的倍数效果通常更好如果有月度周期性w取30附近更合适。论文最终选择的最优模型是单层5个神经元、w23天MAPE为3.9%这个w接近3周的周期长度说明模型在利用三周前的负荷模式来校准当前预测。网格搜索w时我一般从7、14、21、28、35、42这几个值起步先粗搜确定量级再在最优值附近做细粒度搜索。5. LSTM负荷预测避坑记录五个容易翻车的细节5.1 归一化参数全量计算导致验证集信息泄露现象模型在验证集上MAPE能做到2%以内换到测试集直接飙到6%以上差距大得离谱。原因预处理时用全量数据训练验证测试一起算 (X_{min}) 和 (X_{max})测试集的分布信息提前参与了归一化验证表现虚高。解决严格只对训练集计算归一化参数并保存验证集和测试集用同一组参数变换。检查方法也简单打印训练集和测试集的归一化后均值如果差异明显大概率是归一化口径出了问题。5.2 历史窗口w设得过大MAPE不降反升且抖动剧烈现象把w从14天加到45天模型误差不但没降个别月份APE还出现尖峰。原因过长历史窗口把与预测日关联度低的旧数据也塞进输入模型被迫去拟合与当前负荷形态无关的模式论文图6里单层5神经元结构在大w时MAPE剧烈波动正是这个原因。解决对训练集做窗口敏感性分析画出eMAPE随w变化的曲线选择曲线平坦区间内的值有周周期就用7的倍数做网格搜索。我遇到过w取到60天以上的项目最后切回21天反而降了0.3个百分点。5.3 节假日特征只用了0-1变量节日当天预测系统性偏大现象春节、国庆这类长假期前后几天模型预测负荷总是偏高APE最大的点集中在节假日当天。原因is_business这个0-1变量只能区分工作日和非工作日但长假期间负荷形态更像周末模式连续多天非工作日的累积效应对负荷有下拉影响单一变量表达不了。解决把节假日拆成多个特征比如假期第几天、距最近假期还有几天、是否假期前后一天让模型能学到假期前后的过渡效应。论文给出的是基础版特征工程上我一般额外加一个节假日倒数第几天的特征效果立竿见影。5.4 验证集参与多次调参最优结构在测试集上表现不稳定现象同一套网络结构在验证集上反复调参后MAPE持续下降但换到测试集结果波动很大有时差1个百分点以上。原因验证集被反复用来选结构、选w、选回合数实际上验证集信息已通过人工调参间接进入了模型选择过程这就是所谓在验证集上调参调多了验证集也就脏了。解决严格遵守训练集、验证集、测试集三级划分验证集只做一次最终确认如果必须多次调参考虑在验证集里按时间留一段子集做二次验证或者直接上时间序列交叉验证。5.5 隐藏层堆太深预测精度没提升反而更慢现象把LSTM从1层加到3层、每层加到40个神经元训练时间翻了两三倍MAPE却从4.6%变成4.65%基本没有改善。原因这个负荷数据集的复杂度有限单层5个神经元已经能学到核心规律更大的模型容量只带来过拟合风险和训练开销。论文表2里三层10个神经元的4.58%与单层5个神经元的4.60%差距只有0.02个百分点这0.02在工程上完全可以忽略。解决先把模型做小用单层、少量神经元跑通全流程确认特征和数据处理没问题后再逐层加容量每次加容量后要在验证集上确认收益大于0.1个百分点才保留否则回退。6. 把MAPE从4.6%压到3.9%历史窗口网格搜索与多尺度特征技巧论文里最值得打磨的细节是固定w7天时最优MAPE为4.6%单层5个神经元但把w放开到23天后同样结构MAPE降到了3.9%。这说明在LSTM短期负荷预测里历史窗口的取值对精度的影响大于隐藏层结构。我的做法是把网络结构固定下来然后用网格搜索专心找w的最优值。网格不用太密先试w从7、14、21、28、35、42这几个值每组跑完记录验证集MAPE画出变化曲线再在洼地附近加密。以论文数据为例w在7到30天之间MAPE平稳20天后开始出现单层结构的抖动最优落在23天附近这提示最终搜索范围可以收敛到21到28天。多尺度特征是我从论文表1里的per_hour_load和per_max_load这两个特征里衍生出来的经验。论文用历史窗口期内同一时刻负荷和每日最大最小负荷来刻画窗口内的负荷水平工程上还可以再加一层均值聚合把窗口内7天同时刻负荷的中位数和标准差也作为特征加入输入向量。中位数比均值更抗异常点标准差反映负荷波动幅度这两项能让模型感知窗口内的典型负荷水平和稳定程度对突变日的预测有明显改善。特征增加后要注意input_size变了LSTM输入层权重维度也要对应调整# 特征拼接示意以w7天为例 import numpy as np def build_features(load_series, temperature, is_business, w7): features [] targets [] for t in range(w, len(load_series)): # 历史窗口内同一时刻负荷 hist_load [load_series[t - k] for k in range(1, w 1)] # 窗口内负荷中位数与标准差 hist_median np.median(hist_load) hist_std np.std(hist_load) # 横向因素气温、是否工作日、时刻 row hist_load [hist_median, hist_std, temperature[t], is_business[t], t % 24] features.append(row) targets.append(load_series[t]) return np.array(features), np.array(targets)这段代码把纵向历史负荷、窗口聚合统计量、横向外部因素拼成一行特征t % 24把一天内的小时周期编码进去。LSTM要求输入是三维张量(batch_size, seq_len, input_size)所以特征构造完还要做一次窗口切分把连续的一段行按设定步长切成序列样本每个样本的seq_len对应LSTM展开的时间步数。我踩过坑的地方是切分方式如果用滑窗重叠采样数据量会多很多但样本间相关性高容易过拟合如果按不重叠窗口采样数据量骤减。一般折中做法是滑窗步长等于预测步长既保证样本量又控制相关性。做完这些还有最后一道工序用最优回合数重新在训练集加验证集的合并数据上训练一遍再用测试集评估一次确认MAPE稳定在2%到4%区间再出结果。从那以后我每次做负荷预测项目都强制走一遍这个流程先固定小模型跑通特征工程再网格搜索历史窗口最后才碰网络结构。这个顺序帮我避开了好几轮无效调参如果你也在做类似的时间序列预测希望帮到你。本文还有配套的精品资源点击获取
返回列表