ARTICLE DETAIL

资讯详情

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

CNN-BiGRU-Attention省间现货购电需求预测实战

CNN-BiGRU-Attention省间现货购电需求预测实战 简介这份资源是发表于《电力系统及其自动化学报》的网络首发论文面向电力市场分析师、电力行业研究人员及购电策略制定人员聚焦省间现货市场超短期购电需求预测这一实际问题。论文提出融合卷积神经网络、双向门控循环单元与注意力机制的组合预测模型先以Lasso系数法筛选购电需求影响因素再由CNN提取时间序列局部特征、BiGRU捕捉长期依赖关系并借助注意力机制聚焦关键时间步以提升精度仿真实验表明其准确性明显优于单一模型与其他组合模型。资源包为1个PDF文件约930KB完整收录论文正文、摘要、关键词、引用格式及实验数据说明便于读者系统研读模型构建流程、数据处理方法与结果对比。目前已有65人学习适合希望将深度学习组合模型应用于电力现货需求预测的读者参考借鉴。1. 省间现货购电需求预测为什么 CNN-BiGRU-Attention 值得你花时间拆一遍省间现货市场的购电需求预测本质上是一个 15 分钟粒度的超短期时序回归问题。每天 96 个采样点输入维度包含气象、负荷、日期类型等 9 个备选因素输出是下一个时间点的购电需求值。听起来像标准的负荷预测但省间现货场景有几个特殊之处需求波动受省间价差和通道容量约束影响日内峰谷切换频繁且可用训练数据往往只有几个月——江苏省 2022 年 10 月到 2023 年 8 月满打满算 11 个月。这篇发表在《电力系统及其自动化学报》的论文DOI: 10.19635/j.cnki.csu-epsa.001547核心思路是用 Lasso 做特征筛选降维再用 CNN 提局部特征、BiGRU 提双向时序依赖、注意力机制做时间步加权。最终 MAPE 压到 0.90%比单一 BiGRU 降低 1.26 个百分点比 CNN-BiGRU 降低 0.48 个百分点。对于做电力市场分析、购电策略制定或时序预测工程落地的从业者这套组合模型的工程参考价值在于结构不复杂、参数量可控、训练时间可接受而且论文给出了完整的参数配置和对比实验数据复现门槛不高。我拿到这份论文后第一反应不是看结论而是翻到参数表——卷积核 64、BiGRU 神经元 64、滑动窗口 96、批量大小 64。这几个数字决定了你能不能在自己的数据集上跑通。接下来我把论文里的技术路线拆成可执行的步骤顺带把几个容易翻车的地方标出来。2. 从 9 个影响因素到 3 个关键特征Lasso 筛选的工程实现2.1 为什么必须做特征筛选论文列了 9 个备选输入最高气温、最低气温、湿度、降水量、风速、气压、日负荷、日电量、日期类型。如果全部塞进 CNN-BiGRU-Attention输入维度膨胀卷积核需要覆盖更多通道训练样本相对不足时过拟合风险直线上升。论文用 Lasso 回归做筛选正则化参数 λ240 时最低温度、湿度、降水量、风速、气压、日期类型的回归系数被压缩到接近 0最终保留最高温度系数 87.11、日负荷142.41、日电量112.12三个变量。这里有个细节值得注意最低温度被筛掉了但最高温度保留。在省间现货场景下最高温度直接关联空调负荷峰值而最低温度对购电需求的边际影响在江苏这种气候区确实有限。Lasso 的稀疏化不是随便砍而是让数据说话。2.2 Lasso 特征筛选的代码实现import numpy as np from sklearn.linear_model import LassoCV from sklearn.preprocessing import StandardScaler # 假设 X 为 (n_samples, 9) 的特征矩阵y 为购电需求 # 特征顺序最高温, 最低温, 湿度, 降水量, 风速, 气压, 日负荷, 日电量, 日期类型 feature_names [最高温, 最低温, 湿度, 降水量, 风速, 气压, 日负荷, 日电量, 日期类型] # 标准化Lasso 对量纲敏感不标准化会导致系数不可比 scaler StandardScaler() X_scaled scaler.fit_transform(X) # 交叉验证选 lambdacv5 是常用折数 lasso_cv LassoCV(cv5, random_state42, max_iter10000, alphasnp.logspace(-2, 4, 200)) lasso_cv.fit(X_scaled, y) print(f最优 lambda: {lasso_cv.alpha_:.2f}) for name, coef in zip(feature_names, lasso_cv.coef_): print(f{name}: {coef:.5f}) # 筛选系数绝对值大于阈值的特征 threshold 1e-3 selected [name for name, coef in zip(feature_names, lasso_cv.coef_) if abs(coef) threshold] print(f保留特征: {selected})这段代码的逻辑说明StandardScaler做 Z-score 标准化是必须的Lasso 的 L1 惩罚对特征尺度敏感不标准化的话日负荷数值几百和湿度数值几十的系数不可比。LassoCV内部用交叉验证遍历 alpha 序列论文里 λ240 是在原始量纲下的值标准化后对应的 alpha 会不同但筛选出的特征组合应该一致。max_iter设大一些避免不收敛警告。参数说明alphas的范围建议覆盖 1e-2 到 1e4论文的 λ240 落在这个区间内。cv5是折中数据量少时可以用cv3减少计算量。筛选阈值threshold不要设太大1e-3 足够过滤掉数值噪声。2.3 筛选后的数据组织方式论文最终用 3 个特征加购电需求本身构成输入。滑动窗口长度 96意味着每个样本是 96 个时间步 × 4 个通道购电需求 最高温 日负荷 日电量。这里有个容易搞混的地方购电需求既是输入序列的一部分也是预测目标。具体做法是用 t-95 到 t 时刻的 96 个点预测 t1 时刻的值输入包含这 96 个点的购电需求和对应时刻的三个影响因素。def create_sliding_window(data, target_col, feature_cols, window_size96): data: DataFrame包含购电需求和筛选后的特征 target_col: 目标列名 feature_cols: 特征列名列表 window_size: 滑动窗口长度 返回: X shape (samples, window_size, channels), y shape (samples,) X, y [], [] values data[feature_cols].values target data[target_col].values for i in range(window_size, len(data)): # 输入窗口过去 window_size 个时间步的所有特征 X.append(values[i - window_size:i, :]) # 预测目标下一个时间点的购电需求 y.append(target[i]) return np.array(X), np.array(y)逻辑说明窗口从window_size开始滑动每个样本的输入是过去 96 步的全部特征输出是第 97 步的购电需求。注意feature_cols里要包含购电需求列本身因为论文的输入序列同时包含需求和影响因素。参数方面window_size96对应 24 小时96×15 分钟这是论文的选择实际使用时可以根据数据周期调整但建议保持 96 的整数倍以便对齐日周期。3. CNN-BiGRU-Attention 模型搭建逐模块拆解与参数配置3.1 整体结构的数据流论文的模型分四个模块卷积模块 → BiGRU 模块 → 注意力模块 → 回归模块。输入张量形状是(batch, 96, 4)经过一维卷积和最大池化后通道数从 4 扩展到 64时间步长保持不变或减半取决于池化设置。然后 BiGRU 接收卷积输出每个时间步输出 64 维隐藏状态双向拼接后变成 128 维。注意力模块对这 96 个时间步的 128 维特征计算权重加权求和得到一个 128 维的上下文向量。最后全连接层映射到标量输出。论文表 3 给出的参数卷积核数目 64、最大池化池大小 2、卷积层步长 1、BiGRU 层神经元 64、滑动窗口 96、批量大小 64。这些数字直接决定了模型容量和训练速度。3.2 卷积模块的实现细节import torch import torch.nn as nn class CNNModule(nn.Module): def __init__(self, in_channels4, out_channels64, kernel_size3): super().__init__() # 一维卷积在时间维度上滑动提取局部模式 self.conv nn.Conv1d( in_channelsin_channels, out_channelsout_channels, kernel_sizekernel_size, stride1, paddingkernel_size // 2 # 保持时间步长度不变 ) self.relu nn.ReLU() # 最大池化池大小 2时间步减半 self.pool nn.MaxPool1d(kernel_size2, stride2) def forward(self, x): # x: (batch, channels, time_steps) x self.conv(x) x self.relu(x) x self.pool(x) return x # (batch, 64, 48)逻辑说明Conv1d的输入格式是(batch, channels, time_steps)所以需要把原始数据的(batch, 96, 4)转置成(batch, 4, 96)。paddingkernel_size//2保证卷积后时间步不变池化后再减半到 48。论文没有明确说池化后的时间步但池大小 2、步长默认等于池大小时96 步变成 48 步是合理推断。参数说明kernel_size3是时序卷积的常见选择覆盖 45 分钟窗口。如果数据噪声大可以增大到 5 或 7。out_channels64与论文一致显存不够时可以降到 32但会损失特征表达能力。3.3 BiGRU 模块与注意力机制class BiGRUAttention(nn.Module): def __init__(self, input_size64, hidden_size64, num_layers1): super().__init__() self.bigru nn.GRU( input_sizeinput_size, hidden_sizehidden_size, num_layersnum_layers, batch_firstTrue, bidirectionalTrue ) # 双向输出维度是 hidden_size * 2 self.attention_weights nn.Linear(hidden_size * 2, 1) self.softmax nn.Softmax(dim1) def forward(self, x): # x: (batch, time_steps, features) gru_out, _ self.bigru(x) # (batch, time_steps, 128) # 注意力打分每个时间步得到一个标量分数 scores self.attention_weights(gru_out) # (batch, time_steps, 1) weights self.softmax(scores) # 时间步维度归一化 # 加权求和得到上下文向量 context torch.sum(gru_out * weights, dim1) # (batch, 128) return context逻辑说明batch_firstTrue让输入格式变成(batch, time_steps, features)省去转置。BiGRU 输出每个时间步 128 维64 正向 64 反向。注意力层用一个线性层把 128 维映射到 1 维分数再沿时间步维度做 softmax。加权求和后得到 128 维上下文向量送入全连接回归层。参数说明hidden_size64与论文一致。num_layers1是论文隐含的设置层数增加会显著拖慢训练。注意力线性层的初始化用默认的 Kaiming 均匀分布即可不需要特殊处理。3.4 完整模型组装与训练配置class CNNBiGRUAttention(nn.Module): def __init__(self, in_channels4, cnn_out64, gru_hidden64): super().__init__() self.cnn CNNModule(in_channels, cnn_out) self.bigru_attention BiGRUAttention(cnn_out, gru_hidden) self.fc nn.Sequential( nn.Linear(gru_hidden * 2, 32), nn.ReLU(), nn.Linear(32, 1) ) def forward(self, x): # x: (batch, time_steps, channels) - 转置给 CNN x x.permute(0, 2, 1) # (batch, channels, time_steps) x self.cnn(x) # (batch, 64, 48) x x.permute(0, 2, 1) # (batch, 48, 64) context self.bigru_attention(x) # (batch, 128) out self.fc(context) # (batch, 1) return out.squeeze(-1) # 训练配置 model CNNBiGRUAttention() optimizer torch.optim.Adam(model.parameters(), lr1e-3) criterion nn.MSELoss()逻辑说明permute操作在 CNN 和 BiGRU 之间切换数据格式。CNN 需要(batch, channels, time)BiGRU 需要(batch, time, features)。回归模块用两层全连接中间 32 维是论文没有明确但合理的压缩层直接 128→1 参数量太大容易过拟合。参数说明学习率 1e-3 是 Adam 的默认值论文没有给出学习率但在这个参数量级下 1e-3 到 5e-4 都合理。损失函数用 MSE与论文的 RMSE 评价指标一致。批量大小 64 与论文一致显存不够可以降到 32。4. 训练与评估数据划分、归一化和指标计算4.1 数据集划分与归一化论文的划分方式训练集 2022 年 10 月 1 日到 2023 年 6 月 30 日验证集 2023 年 7 月 1 日到 7 月 31 日测试集 2023 年 8 月 1 日到 8 月 31 日。这是严格的时间顺序划分不能打乱否则会造成未来信息泄漏。归一化用最大-最小法公式是x* (x - x_min) / (x_max - x_min)。注意归一化参数必须从训练集计算然后应用到验证集和测试集不能用全量数据的最大最小值。def min_max_normalize(train, val, test, feature_cols): 用训练集的 min/max 归一化所有数据集 scaler_params {} for col in feature_cols: x_min train[col].min() x_max train[col].max() scaler_params[col] (x_min, x_max) train[col] (train[col] - x_min) / (x_max - x_min) val[col] (val[col] - x_min) / (x_max - x_min) test[col] (test[col] - x_min) / (x_max - x_min) return train, val, test, scaler_params逻辑说明scaler_params保存训练集的 min/max预测新数据时用同一套参数反归一化。如果验证集或测试集出现超出训练集范围的值归一化后会超出 [0,1]这是正常的说明模型遇到了训练时没见过的极端情况。4.2 评价指标计算论文用 MAPE、RMSE、R² 三个指标。MAPE 对接近零的真实值敏感购电需求一般不会接近零所以 MAPE 可用。RMSE 量纲与原始数据一致直观反映误差大小。R² 衡量拟合优度。def calculate_metrics(y_true, y_pred): y_true, y_pred: 反归一化后的原始量纲值 mape np.mean(np.abs((y_true - y_pred) / y_true)) * 100 rmse np.sqrt(np.mean((y_true - y_pred) ** 2)) ss_res np.sum((y_true - y_pred) ** 2) ss_tot np.sum((y_true - np.mean(y_true)) ** 2) r2 1 - ss_res / ss_tot return {MAPE: mape, RMSE: rmse, R2: r2}逻辑说明计算指标前必须反归一化否则 RMSE 没有物理意义。MAPE 公式里分母是y_true如果真实值有零会报错实际购电需求数据不会有零值。R² 越接近 1 越好论文里 CNN-BiGRU-Attention 达到 0.976。4.3 论文对比实验结果解读论文表 4 给出了六种模型的对比模型MAPE%RMSE%R²BiLSTM2.655.350.950BiGRU2.165.040.956CNN-BiLSTM1.794.600.963CNN-BiGRU1.384.140.970CNN-BiLSTM-Attention2.244.740.961CNN-BiGRU-Attention0.903.720.976几个值得注意的点BiGRU 比 BiLSTM 的 MAPE 低 0.49 个百分点训练时间也更短这是论文选 BiGRU 而非 BiLSTM 的理由。CNN-BiGRU 比纯 BiGRU 的 MAPE 降低 0.78 个百分点说明卷积提局部特征确实有用。但 CNN-BiLSTM-Attention 的 MAPE 反而比 CNN-BiLSTM 高说明注意力机制不是万能药加在 LSTM 上可能引入额外噪声。只有在 BiGRU 基础上加注意力才带来显著提升1.38% → 0.90%。这个对比结果提醒我们注意力机制的效果依赖于底层时序特征提取器的质量。BiGRU 的门控结构比 LSTM 更简洁参数更少与注意力的配合更好。5. 避坑与排查复现这套模型时最容易翻车的五个地方5.1 归一化参数从全量数据计算现象训练集 loss 正常下降但验证集和测试集指标异常差MAPE 超过 10%。原因用全量数据的 min/max 做归一化验证集和测试集的信息泄漏到了训练过程中。模型在训练时“看到”了未来数据的范围。解决严格用训练集的 min/max 归一化所有数据集。验证集和测试集出现超出 [0,1] 的值是正常的不要重新缩放。5.2 滑动窗口跨越数据集边界现象测试集第一个样本的输入窗口包含了训练集最后几个时间点预测结果异常好。原因构建滑动窗口时没有在数据集划分处切断窗口跨越了训练集和测试集的边界。解决先按时间划分数据集再分别构建滑动窗口。测试集的第一个窗口只能从测试集内部取数据不足 96 步的样本丢弃。5.3 注意力权重全为均匀分布现象训练完成后可视化注意力权重发现 96 个时间步的权重几乎相等没有聚焦效果。原因注意力层的输入特征区分度不够或者训练轮数不足注意力层还没学到有效的打分函数。解决检查 BiGRU 的输出是否有足够的方差。如果 BiGRU 隐藏状态趋同注意力层无法区分时间步。可以尝试增大 BiGRU 的 hidden_size或者增加训练轮数。另外注意力层的初始化不要用全零默认初始化即可。5.4 批量大小与学习率不匹配现象训练 loss 震荡严重无法收敛。原因批量大小 64 配学习率 1e-3 在某些数据集上偏大梯度更新步长过大。解决批量大小减半到 32学习率降到 5e-4。或者保持批量大小加梯度裁剪torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm1.0)。5.5 池化层导致时间步信息丢失现象模型对短时波动不敏感预测曲线过于平滑。原因最大池化池大小 2 把 96 步压缩到 48 步15 分钟粒度的细节被丢弃。解决如果数据波动剧烈去掉池化层或改用平均池化。论文用池化是为了减少计算量但在超短期预测中时间分辨率很重要。可以尝试池大小 1即不池化代价是训练时间增加。6. 进阶技巧用注意力权重做特征重要性分析论文只把注意力机制当作提升精度的工具但注意力权重本身携带了时间步重要性的信息。我习惯在模型训练完成后把测试集样本的注意力权重导出来按时间步求平均看看模型在一天 96 个时间点里更关注哪些时段。def extract_attention_weights(model, dataloader): 提取测试集所有样本的注意力权重 model.eval() all_weights [] with torch.no_grad(): for X_batch, _ in dataloader: # 手动前向传播保留中间权重 x X_batch.permute(0, 2, 1) x model.cnn(x) x x.permute(0, 2, 1) gru_out, _ model.bigru_attention.bigru(x) scores model.bigru_attention.attention_weights(gru_out) weights model.bigru_attention.softmax(scores) all_weights.append(weights.squeeze(-1).cpu().numpy()) # 拼接所有批次按时间步求平均 all_weights np.concatenate(all_weights, axis0) # (n_samples, time_steps) avg_weights all_weights.mean(axis0) # (time_steps,) return avg_weights # 可视化 import matplotlib.pyplot as plt avg_weights extract_attention_weights(model, test_loader) plt.figure(figsize(12, 4)) plt.bar(range(len(avg_weights)), avg_weights) plt.xlabel(时间步15分钟间隔) plt.ylabel(平均注意力权重) plt.title(模型关注的时间步分布) plt.savefig(attention_weights.png, dpi150)逻辑说明extract_attention_weights手动执行前向传播在注意力层处截取权重。all_weights的形状是(样本数, 时间步数)沿样本维度求平均得到每个时间步的平均权重。可视化后可以看到模型是否在特定时段如早晚高峰分配了更高权重。参数说明如果注意力权重过于集中在一两个时间步说明 softmax 温度过低可以尝试在 softmax 前除以一个温度系数如scores / temperaturetemperature 1 使分布更平滑。如果权重过于均匀说明模型没有学到有效的时间聚焦需要检查 BiGRU 输出。这个分析的实际价值在于如果模型持续关注某些时段而这些时段恰好对应省间价差较大的时段说明模型学到了市场逻辑预测结果更可信。如果注意力分布与业务认知不符可能需要检查输入特征是否遗漏了关键变量。从那以后我每次复现时序注意力模型都会强制走一遍注意力权重可视化确认模型关注的时间步和业务逻辑对得上再去看 MAPE 指标。希望帮到你。本文还有配套的精品资源点击获取
返回列表