2025.3.9机器学习笔记:文献阅读

2025.3.9周报

  • 一、文献阅读
    • 题目信息
    • 摘要
    • Abstract
    • 创新点
    • 网络架构
    • 实验
    • 结论
    • 不足以及展望

一、文献阅读

题目信息

  • 题目: Time-series generative adversarial networks for flood forecasting
  • 期刊: Journal of Hydrology
  • 作者: Peiyao Weng, Yu Tian, Yingfei Liu, Ying Zheng
  • 发表时间: 2023/5/20
  • 文章链接: https://www.sciencedirect.com/science/article/pii/S0022169423006443?via%3Dihub

摘要

洪水每年对全世界造成了巨大的损失,有效的洪水预警是重要防洪方式,但是现有洪水预测方法并不可靠,比如,传统的物理计算方法和数据驱动模型需大量水文和地貌数据,又因为极端洪水事件观测数据有限,这会导致模型的预测不准确。本论文基于时间序列GANs,探究其在洪水时间序列生成及预报中的作用,利用时间序列生成对抗网络进行洪水预测,应用TimeGAN和RTSGAN生成合成洪水时间序列。以中国西江流域为例,实验结果表明TimeGAN能准确高效模拟多站点洪水序列的时空相关性,RTSGAN在长序列时表现更优,且合成数据集可减少常规深度学习模型的预测误差。这种方法为解决洪水预报中数据稀缺问题提供了新思路,对提升洪水预报具有重要作用,有助于减少洪水造成的损失。

Abstract

Floods cause substantial losses worldwide each year, making effective flood warning systems a critical component of flood prevention. However, existing flood prediction methods are often unreliable. For instance, traditional physically-based computational approaches and data-driven models require extensive hydrological and geomorphological data. Moreover, the limited availability of observational data for extreme flood events often leads to inaccurate predictions. This paper investigates the application of time series Generative Adversarial Networks (GANs) in generating and forecasting flood time series. Specifically, we employ TimeGAN and RTSGAN to produce synthetic flood time series data. Using the Xijiang River Basin in China as a case study, experimental results demonstrate that TimeGAN can accurately and efficiently simulate the spatiotemporal correlations of multi-site flood sequences. RTSGAN, on the other hand, exhibits superior performance for longer sequences. Furthermore, the synthetic datasets generated by these models can reduce prediction errors in conventional deep learning approaches. This methodology offers a novel solution to the challenge of data scarcity in flood forecasting, significantly enhancing flood prediction accuracy and contributing to the mitigation of flood-related damages.

创新点

作者首次将时间序列GANs应用于洪水时间序列生成中,以提升洪水预报模型精度,其利用历史序列数据生成新数据,且无需预处理,生成的序列保留原始时间特征。

网络架构

在论文第3.1节“Flood generating model”中,提到在生成合成洪水数据之前,需要对原始洪水时间序列进行预处理。数据为洪水时间序列,包含多个洪水事件𝑘,特征维度 𝑛,时间步长𝑚,窗口大小𝑤,序列长度𝐿。将原始洪水时间序列通过滑动窗口的方式分割成三维数据,其表示为: [ ∑ i = 1 k ( L i − w + 1 ) , n , w ] [\sum_{i=1}^{k}\left(L_{i}-w+1\right), n, w] [i=1k(Liw+1),n,w]
窗口大小w决定每次处理的数据长度,论文中将小时尺度定为48小时每3小时一个时间步,则分为16个时间步;日尺度则为9天,则分为9个时间步;
论文中“the sliding step 𝑚 is set to 1”,将步长m设为1,表示窗口每次滑动1个时间步,生成重叠窗口。
举个例子:对于第𝑖个洪水事件,时间序列长度为 L i L_i Li,设 L i = 100 L_i = 100 Li=100(洪水持续了100个小事),窗口大小w=16,步长m=1,有三个特征,即n=3。
则第一个窗口时间步1到16;第二个窗口时间步2到17;最后一个窗口时间步85到100。​
总窗口数则为100−16+1=85,且一个窗口是一个二维矩阵[n,w]。
所以这个三维矩阵表达为: [ ∑ i = 1 k ( L i − w + 1 ) , n , w ] [\sum_{i=1}^{k}\left(L_{i}-w+1\right), n, w] [i=1k(Liw+1),n,w] = [85,3,16]
在这里插入图片描述
TimeGAN包含嵌入函数、恢复函数、序列生成器和序列鉴别器的生成模型,通过有监督损失和无监督损失的学习嵌入空间对抗性和联合训练,让模型得以同时学习编码特征、生成表示和跨时间迭代。有关于TimeGAN的知识点,我在之前的博客记录过,这里就不再赘述了,大家需要的话可以点击这个链接查看:https://blog.csdn.net/Zcymatics/article/details/145011621?spm=1001.2014.3001.5501
在这里插入图片描述
接下来我们详细分析一下作者提到的RTSGAN,其全称为“Recurrent Time-Series Generative Adversarial Network”,它是TimeGAN的改进版本,专门用于生成高质量时间序列数据。
其核心是通过结合WGAN 和自回归解码器,克服了传统TimeGAN在长序列生成中的不稳定性和长序列信息捕捉能力弱问题。
传统GAN使用的是JS散度或KL散度优化生成分布与真实分布的相似性。想要了解GAN可以去我这篇博客看一下原理:https://blog.csdn.net/Zcymatics/article/details/145011685?spm=1001.2014.3001.5501
而WGAN使用Wasserstein距离替代JS散度,减少模式崩塌,提高训练稳定性。

模型坍塌是指模型在训练过程中逐渐失去多样性和泛化能力,导致性能严重退化甚至无法继续优化。

在这里插入图片描述
其损失函数被定义为: L = E r ∼ P r [ D ( r ) ] − E r ^ ∼ P g [ D ( r ^ ) ] L=E_{r \sim P_{r}}[D(r)]-E_{\hat{r} \sim P_{g}}[D(\hat{r})] L=ErPr[D(r)]Er^Pg[D(r^)]
D是判别器 E r ∼ P r [ D ( r ) ] E_{r \sim P_{r}}[D(r)] ErPr[D(r)]是真实样本𝑟通过𝐷的期望输出; E r ^ ∼ P g [ D ( r ^ ) ] E_{\hat{r} \sim P_{g}}[D(\hat{r})] Er^Pg[D(r^)]合成样本 r ^ \hat{r} r^通过𝐷的期望输出。

说完了Wasserstein距离,下面来说一下RTSGAN的另一个改进点:
自回归编码器
TimeGAN中,使用的是嵌入函数和恢复函数完成。其嵌入函数是逐时间步生成潜在序列𝐻,每个时间步都有一个对应的潜在表示 h t h_t ht ;其恢复函数从整个潜在序列𝐻一次性生成重建序列 X ^ \hat X X^
RTSGAN中使用的则是自回归编码器和解码器。编码器同样负责将时间序列X映射到潜在空间,但其目标是生成一个固定维度的潜在表示𝑟,而不是逐时间步的潜在序列𝐻;其解码器从潜在表示逐步生成时间序列(不是一次性输出),采用自回归方式生成每个时间步的输出。
TimeGAN的一次性生成会导致长序列的时间相关性可能被削弱。RTSGAN中自回归解码器通过逐步生成的方式学习时间依赖性,每一步的生成依赖于前一步的输出,更加能够捕捉时间动态变化。
在这里插入图片描述
下图是论文工作的总体的流程图:
首先数据经过预处理后给TimeGAN和RTSGAN生成数据,然后真实的训练数据和生成数据进入滑动窗口。滑动窗口将真实和合成数据分割成两个部分,为监督学习提供数据,真实数据为covariates,如 x t − 2 1 , x t − 2 2 , x t − 2 3 x_{t-2}^1, x_{t-2}^2, x_{t-2}^3 xt21,xt22,xt23,绿色框为GAN生成数据y,如 y t y_t yt,每个实例包含输入和输出。这些数据对供GBRT和LSTM训练。最后两个预测模型输出预测值与真实值对比,得出评估指标。
在这里插入图片描述

实验

本文围绕时间序列生成对抗网络在洪水预测中的应用展开实验,
论文的评价指标如下图所示,其中比较陌生的有:
1、皮尔逊相关系数,其用于衡量预测值与观测值的线性相关性,值越大越好(最大值为1):
O C = ∑ i = 1 n ( F i − F ˉ ) ( O i − O ˉ ) ∑ i = 1 n ( F i − F ˉ ) 2 ∑ i = 1 n ( O i − O ˉ ) 2 O C=\frac{\sum_{i=1}^n\left(F_i-\bar{F}\right)\left(O_i-\bar{O}\right)}{\sqrt{\sum_{i=1}^n\left(F_i-\bar{F}\right)^2} \sqrt{\sum_{i=1}^n\left(O_i-\bar{O}\right)^2}} OC=i=1n(FiFˉ)2 i=1n(OiOˉ)2 i=1n(FiFˉ)(OiOˉ)
F i F_i Fi为预测值; O i O_i Oi为观测值; F ˉ \bar{F} Fˉ O ˉ \bar{O} Oˉ分别为预测和观测均值。
2、平均绝对相对误差,计算预测值与观测值的相对偏差,值越小越好(0为最小值):
A A R E = 1 n ∑ i = 1 n ∣ F i p − O i p O i p ∣ A A R E=\frac{1}{n} \sum_{i=1}^n\left|\frac{F_i^p-O_i^p}{O_i^p}\right| AARE=n1i=1n OipFipOip
𝑛为样本数; F i p F_i^p Fip为预测值; O i p O_i^p Oip为观测值。
3、预测区间覆盖概率,衡量观测值落入预测区间的比例,最佳值为1:
P I C P = 1 n ∑ i = 1 n ε i , ε i = 1 P I C P=\frac{1}{n} \sum_{i=1}^n \varepsilon_i, \quad \varepsilon_i=1 PICP=n1i=1nεi,εi=1 if O i ∈ [ L i , U i ] O_i \in\left[L_i, U_i\right] Oi[Li,Ui], else 0
L i L_i Li U i U_i Ui为预测区间的上下界。
4、预测区间归一化平均宽度,评估预测区间的宽度,最佳值为0:
P I N A W = 1 n R ∑ i = 1 n ( U i − L i ) , R = max ⁡ ( O i ) − min ⁡ ( O i ) PINAW =\frac{1}{n R} \sum_{i=1}^n\left(U_i-L_i\right), \quad R=\max \left(O_i\right)-\min \left(O_i\right) PINAW=nR1i=1n(UiLi),R=max(Oi)min(Oi)
R为观测值范围;
5、覆盖宽度综合准则,平衡覆盖率和区间宽度,PICP低于𝜇时施加指数惩罚,0为最佳值:
C W C = P I N A W ( 1 + γ e η ( μ − P I C P ) ) , γ ( P I C P ) = 1 C W C=P I N A W\left(1+\gamma e^{\eta(\mu-P I C P)}\right), \quad \gamma(P I C P)=1 CWC=PINAW(1+γeη(μPICP)),γ(PICP)=1 if P I C P < μ P I C P<\mu PICP<μ, else 0
μ为期望覆盖率;𝜂为惩罚系数;
在这里插入图片描述
结果如下:
论文通过二维t-SNE和PCA两种降维方法对原始洪水时间序列、TimeGAN生成的合成序列以及RTSGAN生成的合成序列进行了可视化分析。结果表明,RTSGAN生成的合成序列在分布上与原始数据集更为接近,表现为数据点簇的形状和密度更贴近原始数据,而TimeGAN生成的序列分布则稍显分散,偏离原始数据的特征。此外,RTSGAN生成的数据点不仅更集中,还展现出更高的多样性。
在这里插入图片描述
图6通过热图形式展示了原始数据集、TimeGAN和RTSGAN生成序列在不同时间滞后 𝜏 下的时间相关性对比。热图中,颜色深浅表示相关系数的大小,RTSGAN的热图模式与原始数据高度一致,尤其是在日尺度上,梧州站点的合成序列时间相关系数几乎完全重合原始数据。这表明RTSGAN能够精确再现洪水序列的时间依赖性,例如洪峰的到达时间和衰退过程。
在小时尺度上,由于时间步长更小,序列长度增加,对模型捕捉长期依赖性的要求更高。RTSGAN依然表现出色,其热图显示的空间相关性和时间相关性均优于TimeGAN。这可能是由于RTSGAN的自回归解码器设计,能够逐步生成序列并保留长期依赖。RTSGAN训练时间更短。
在这里插入图片描述
在多时间步预测任务中,论文比较了GBRT、LSTM、QRLSTM等模型的性能,图7展示了日尺度下各模型在T、T+1、T+2的评估指标箱线图,包括OC、AARE等。结果显示,LSTM在所有预测步长中的OC最高,AARE最低,且随着预测期从T到T+2增加,其优势逐渐扩大。例如,箱线图中LSTM的中位数OC值可能接近1,离群点较少,而其他模型的OC分布更分散,AARE更高。LSTM“三门”机制使LSTM能够有效捕捉洪水时间序列中的长期依赖关系。相比之下,GBRT基于窗口的特征提取更适合短期依赖,而QRLSTM在不确定性预测上虽有优势,但在点预测准确性上不如标准LSTM。
在这里插入图片描述
RTSGAN生成的合成数据集能显著提升基于窗口的GBRT模型性能,尤其在较长预测期。在24小时预测中,GBRT - RTSGAN在CC和NSE指标上分别比GBRT高2.08%和6.74%,RMSE降低,AARE减少56.52%。而TimeGAN对GBRT的改进效果有限且不稳定,其合成训练集甚至会导致误差范围增大。合成数据集对LSTM的有效性随预测期增加而急剧下降。
在这里插入图片描述
SHAP分析用于解释模型预测中各特征的重要性,通过SHAP分析发现,GBRT和GBRT - RTSGAN模型使用几乎相同的影响因素进行预测,且形状值模式趋势一致;而GBRT - TimeGAN从T + 5步开始与GBRT的形状值模式差异较大。
在这里插入图片描述
引入合成训练数据集可帮助QRLSTM模型获得更低的PINAW,但会降PICP,只有少数情况能在保持区间覆盖的同时减小区间宽度。图12结果显示,使用RTSGAN或TimeGAN的合成数据后,QRLSTM的PINAW降低,例如从0.15降至0.10,表明预测区间更窄、更精确。但是PICP从0.95降至0.85,说明部分观测值未被区间覆盖。这种权衡表明合成数据增强了模型的准确性,但牺牲了覆盖率。只有少数情况实现了PINAW降低的同时保持PICP接0.9。
随着合成数据集数量增加,PINAW和PICP降低,模型的CWC下降。RTSGAN对PINAW的影响更大,表明可通过调节假样本数量使预测区间更灵活、易调整。尽管合成训练集在QRLSTM中表现不佳,但在洪水峰值处较窄的预测区间是可取的。
在这里插入图片描述

代码如下:

import numpy as np  
import torch  
import torch.nn as nn  
import torch.optim as optim  # 导入PyTorch的优化器模块
from sklearn.ensemble import GradientBoostingRegressor  # 导入sklearn的GBRT模型
from sklearn.metrics import mean_squared_error  # 导入sklearn的均方误差计算函数
import matplotlib.pyplot as plt  # 设置随机种子,确保结果可重复
np.random.seed(42)
torch.manual_seed(42)# 定义数据参数
n_samples = 1755  # 样本数量,参考论文小时尺度数据
n_features = 3  # 特征数量(假设流量、降雨量等)
seq_len = 16  # 序列长度(窗口大小,48小时,每3小时一个时间步)# 生成模拟洪水时间序列数据,假设数据服从正弦波+噪声的形式
time_steps = np.arange(seq_len)  # 创建时间步数组
data = np.zeros((n_samples, seq_len, n_features))  # 初始化数据数组
for i in range(n_samples):for f in range(n_features):# 生成正弦波数据,模拟周期性洪水特征data[i, :, f] = np.sin(0.1 * time_steps + np.random.uniform(0, 2 * np.pi)) + np.random.normal(0, 0.1, seq_len)# 将数据转换为PyTorch张量
data = torch.FloatTensor(data)  # 转换为浮点张量,形状为[n_samples, seq_len, n_features]# 定义GRU网络类,作为TimeGAN的基础模块
class GRU(nn.Module):def __init__(self, input_dim, hidden_dim, num_layers):super(GRU, self).__init__()self.hidden_dim = hidden_dim  # 设置隐藏层维度self.num_layers = num_layers  # 设置GRU层数self.gru = nn.GRU(input_dim, hidden_dim, num_layers, batch_first=True)  # 定义GRU层def forward(self, x):# 初始化隐藏状态h0 = torch.zeros(self.num_layers, x.size(0), self.hidden_dim).to(x.device)# 前向传播out, _ = self.gru(x, h0)return out# 定义TimeGAN模型
class TimeGAN(nn.Module):def __init__(self, input_dim, hidden_dim, num_layers):super(TimeGAN, self).__init__()self.hidden_dim = hidden_dim  # 设置隐藏层维度self.input_dim = input_dim  # 设置输入维度# 嵌入函数(Embedding Function)self.embedder = GRU(input_dim, hidden_dim, num_layers)  # 定义嵌入函数,使用GRU网络# 恢复函数(Recovery Function)self.recovery = nn.Sequential(nn.Linear(hidden_dim, input_dim),  # 线性层,将隐藏状态映射回输入维度nn.Sigmoid()  # Sigmoid激活,确保输出在[0, 1]范围内)# 生成器(Generator)self.generator = GRU(hidden_dim, hidden_dim, num_layers)  # 定义生成器,使用GRU网络self.gen_output = nn.Linear(hidden_dim, hidden_dim)  # 线性层,生成潜在表示# 判别器(Discriminator)self.discriminator = GRU(hidden_dim, hidden_dim, num_layers)  # 定义判别器,使用GRU网络self.dis_output = nn.Linear(hidden_dim, 1)  # 线性层,输出判别结果def forward(self, x):# 嵌入:将输入数据映射到潜在空间h = self.embedder(x)  # 通过嵌入函数生成潜在表示h# 恢复:从潜在空间重建输入数据x_tilde = self.recovery(h)  # 通过恢复函数重建数据return h, x_tildedef generate(self, z):# 生成器:从噪声生成潜在表示h_hat = self.generator(z)  # 通过生成器生成潜在表示h_hat = self.gen_output(h_hat)  # 映射到潜在空间# 恢复:从生成的潜在表示生成数据x_hat = self.recovery(h_hat)  # 通过恢复函数生成合成数据return x_hat# 设置模型参数
input_dim = n_features  # 输入维度(特征数)
hidden_dim = 24  # 隐藏层维度,参考论文中的设置
num_layers = 3  # GRU层数# 初始化TimeGAN模型
timegan = TimeGAN(input_dim, hidden_dim, num_layers)# 定义损失函数
mse_loss = nn.MSELoss()  # 均方误差损失,用于自编码和监督损失
bce_loss = nn.BCEWithLogitsLoss()  # 二元交叉熵损失,用于对抗损失# 定义优化器
optimizer_E = optim.Adam(list(timegan.embedder.parameters()) + list(timegan.recovery.parameters()), lr=0.001)  # 嵌入和恢复优化器
optimizer_G = optim.Adam(list(timegan.generator.parameters()) + list(timegan.gen_output.parameters()), lr=0.001)  # 生成器优化器
optimizer_D = optim.Adam(list(timegan.discriminator.parameters()) + list(timegan.dis_output.parameters()), lr=0.001)  # 判别器优化器# 训练TimeGAN
num_epochs = 100  # 训练轮数
batch_size = 128  # 批次大小
for epoch in range(num_epochs):for i in range(0, n_samples, batch_size):# 获取批次数据batch_data = data[i:i + batch_size].cuda() if torch.cuda.is_available() else data[i:i + batch_size]# 训练嵌入和恢复(自编码损失)optimizer_E.zero_grad()  # 清零梯度h, x_tilde = timegan(batch_data)  # 前向传播,得到潜在表示和重建数据recon_loss = mse_loss(x_tilde, batch_data)  # 计算自编码损失recon_loss.backward()  # 反向传播optimizer_E.step()  # 更新参数# 训练判别器optimizer_D.zero_grad()  # 清零梯度real_h = timegan.embedder(batch_data)  # 嵌入真实数据real_logit = timegan.dis_output(timegan.discriminator(real_h))  # 判别真实数据z = torch.randn(batch_size, seq_len, hidden_dim)  # 生成随机噪声fake_x = timegan.generate(z)  # 生成合成数据fake_h = timegan.embedder(fake_x)  # 嵌入合成数据fake_logit = timegan.dis_output(timegan.discriminator(fake_h))  # 判别合成数据d_loss = bce_loss(real_logit, torch.ones_like(real_logit)) + bce_loss(fake_logit, torch.zeros_like(fake_logit))  # 计算判别器损失d_loss.backward()  # 反向传播optimizer_D.step()  # 更新参数# 训练生成器optimizer_G.zero_grad()  # 清零梯度z = torch.randn(batch_size, seq_len, hidden_dim)  # 生成随机噪声fake_x = timegan.generate(z)  # 生成合成数据fake_h = timegan.embedder(fake_x)  # 嵌入合成数据fake_logit = timegan.dis_output(timegan.discriminator(fake_h))  # 判别合成数据g_loss = bce_loss(fake_logit, torch.ones_like(fake_logit))  # 计算生成器对抗损失# 计算监督损失(使用真实数据监督生成器)supervised_loss = mse_loss(fake_x[:, 1:, :], fake_x[:, :-1, :])  # 监督损失:预测下一步total_g_loss = g_loss + 0.1 * supervised_loss  # 总生成器损失(对抗损失+监督损失)total_g_loss.backward()  # 反向传播optimizer_G.step()  # 更新参数# 打印损失if (epoch + 1) % 10 == 0:print(f"Epoch {epoch+1}/{num_epochs}, Recon Loss: {recon_loss.item():.4f}, D Loss: {d_loss.item():.4f}, G Loss: {total_g_loss.item():.4f}")# 生成合成数据
with torch.no_grad():z = torch.randn(n_samples, seq_len, hidden_dim)  # 生成随机噪声synthetic_data_timegan = timegan.generate(z)  # 生成合成数据
synthetic_data_timegan = synthetic_data_timegan.cpu().numpy()  # 转换为numpy数组# 定义RTSGAN模型
class RTSGAN(nn.Module):def __init__(self, input_dim, hidden_dim, num_layers):super(RTSGAN, self).__init__()self.hidden_dim = hidden_dim  # 设置隐藏层维度self.input_dim = input_dim  # 设置输入维度# 自回归编码器(Autoregressive Encoder)self.encoder = GRU(input_dim, hidden_dim, num_layers)  # 定义编码器,使用GRU网络self.encoder_output = nn.Linear(hidden_dim * seq_len, hidden_dim)  # 线性层,压缩为固定维度潜在表示# 自回归解码器(Autoregressive Decoder)self.decoder = GRU(input_dim, hidden_dim, num_layers)  # 定义解码器,使用GRU网络self.decoder_output = nn.Linear(hidden_dim, input_dim)  # 线性层,生成输出数据# 判别器(Critic for WGAN)self.critic = GRU(hidden_dim, hidden_dim, num_layers)  # 定义判别器,使用GRU网络self.critic_output = nn.Linear(hidden_dim, 1)  # 线性层,输出Wasserstein距离def encode(self, x):# 编码:将输入序列压缩为固定维度潜在表示h = self.encoder(x)  # 通过编码器生成隐藏状态h = h.reshape(h.size(0), -1)  # 展平隐藏状态r = self.encoder_output(h)  # 压缩为固定维度潜在表示return rdef decode(self, r):# 解码:从潜在表示生成序列batch_size = r.size(0)  # 获取批次大小# 初始化解码器输入x_hat = torch.zeros(batch_size, seq_len, self.input_dim).to(r.device)  # 初始化生成序列h = r.unsqueeze(1).repeat(1, seq_len, 1)  # 将潜在表示扩展到序列长度# 自回归解码for t in range(seq_len):h_t = self.decoder(x_hat[:, :t+1, :])[:, -1, :]  # 获取当前时间步的隐藏状态x_hat[:, t, :] = self.decoder_output(h_t)  # 生成当前时间步的输出return x_hatdef forward(self, x):# 前向传播:编码+解码r = self.encode(x)  # 编码x_tilde = self.decode(r)  # 解码return r, x_tilde# 初始化RTSGAN模型
rtsgan = RTSGAN(input_dim, hidden_dim, num_layers)# 定义优化器
optimizer_E = optim.Adam(list(rtsgan.encoder.parameters()) + list(rtsgan.decoder.parameters()), lr=0.001)  # 编码器和解码器优化器
optimizer_G = optim.Adam(list(rtsgan.decoder.parameters()), lr=0.001)  # 生成器优化器
optimizer_C = optim.Adam(list(rtsgan.critic.parameters()) + list(rtsgan.critic_output.parameters()), lr=0.001)  # 判别器优化器# WGAN-GP的梯度惩罚
def gradient_penalty(critic, real, fake):alpha = torch.rand(real.size(0), 1, 1).to(real.device)  # 随机插值系数interpolates = alpha * real + (1 - alpha) * fake  # 插值数据interpolates.requires_grad_(True)  # 允许计算梯度critic_inter = critic(interpolates)  # 判别插值数据gradients = torch.autograd.grad(outputs=critic_inter, inputs=interpolates,grad_outputs=torch.ones_like(critic_inter),create_graph=True, retain_graph=True)[0]  # 计算梯度gradients = gradients.view(gradients.size(0), -1)  # 展平梯度gradient_norm = gradients.norm(2, dim=1)  # 计算梯度范数gp = ((gradient_norm - 1) ** 2).mean()  # 计算梯度惩罚return gp# 训练RTSGAN
lambda_gp = 10  # 梯度惩罚系数,参考论文
for epoch in range(num_epochs):for i in range(0, n_samples, batch_size):# 获取批次数据batch_data = data[i:i + batch_size].cuda() if torch.cuda.is_available() else data[i:i + batch_size]# 训练编码器和解码器(自编码损失)optimizer_E.zero_grad()  # 清零梯度r, x_tilde = rtsgan(batch_data)  # 前向传播,得到潜在表示和重建数据recon_loss = mse_loss(x_tilde, batch_data)  # 计算自编码损失recon_loss.backward()  # 反向传播optimizer_E.step()  # 更新参数# 训练判别器(WGAN-GP)optimizer_C.zero_grad()  # 清零梯度real_r = rtsgan.encode(batch_data)  # 编码真实数据real_h = rtsgan.critic(real_r.unsqueeze(1).repeat(1, seq_len, 1))  # 判别真实数据real_score = rtsgan.critic_output(real_h)  # 计算真实数据得分z = torch.randn(batch_size, hidden_dim)  # 生成随机噪声fake_x = rtsgan.decode(z)  # 生成合成数据fake_r = rtsgan.encode(fake_x)  # 编码合成数据fake_h = rtsgan.critic(fake_r.unsqueeze(1).repeat(1, seq_len, 1))  # 判别合成数据fake_score = rtsgan.critic_output(fake_h)  # 计算合成数据得分gp = gradient_penalty(rtsgan.critic, real_r.unsqueeze(1).repeat(1, seq_len, 1), fake_r.unsqueeze(1).repeat(1, seq_len, 1))  # 计算梯度惩罚c_loss = fake_score.mean() - real_score.mean() + lambda_gp * gp  # WGAN-GP损失c_loss.backward()  # 反向传播optimizer_C.step()  # 更新参数# 训练生成器optimizer_G.zero_grad()  # 清零梯度z = torch.randn(batch_size, hidden_dim)  # 生成随机噪声fake_x = rtsgan.decode(z)  # 生成合成数据fake_r = rtsgan.encode(fake_x)  # 编码合成数据fake_h = rtsgan.critic(fake_r.unsqueeze(1).repeat(1, seq_len, 1))  # 判别合成数据fake_score = rtsgan.critic_output(fake_h)  # 计算合成数据得分g_loss = -fake_score.mean()  # 生成器损失(WGAN)g_loss.backward()  # 反向传播optimizer_G.step()  # 更新参数# 打印损失if (epoch + 1) % 10 == 0:print(f"Epoch {epoch+1}/{num_epochs}, Recon Loss: {recon_loss.item():.4f}, C Loss: {c_loss.item():.4f}, G Loss: {g_loss.item():.4f}")# 生成合成数据
with torch.no_grad():z = torch.randn(n_samples, hidden_dim)  # 生成随机噪声synthetic_data_rtsgan = rtsgan.decode(z)  # 生成合成数据
synthetic_data_rtsgan = synthetic_data_rtsgan.cpu().numpy()  # 转换为numpy数组# 准备监督学习数据
def prepare_supervised_data(data, window_size):inputs, targets = [], []  # 初始化输入和目标列表data = data.reshape(data.shape[0], -1)  # 展平数据,形状为[n_samples, seq_len * n_features]for i in range(len(data) - window_size):inputs.append(data[i:i + window_size].flatten())  # 提取输入窗口targets.append(data[i + window_size, -1])  # 提取目标(最后一个特征)return np.array(inputs), np.array(targets)# 准备真实数据和合成数据
window_size = 3  # 窗口大小,参考图4
real_inputs, real_targets = prepare_supervised_data(data.numpy(), window_size)  # 准备真实数据
syn_inputs_timegan, syn_targets_timegan = prepare_supervised_data(synthetic_data_timegan, window_size)  # 准备TimeGAN合成数据
syn_inputs_rtsgan, syn_targets_rtsgan = prepare_supervised_data(synthetic_data_rtsgan, window_size)  # 准备RTSGAN合成数据# 混合真实和合成数据
mixed_inputs = np.concatenate([real_inputs, syn_inputs_rtsgan], axis=0)  # 混合真实和RTSGAN数据
mixed_targets = np.concatenate([real_targets, syn_targets_rtsgan], axis=0)  # 混合目标# 训练GBRT模型
gbrt = GradientBoostingRegressor(n_estimators=100, random_state=42)  # 初始化GBRT模型
gbrt.fit(mixed_inputs, mixed_targets)  # 训练GBRT模型
gbrt_pred = gbrt.predict(real_inputs)  # 使用真实数据预测
gbrt_mse = mean_squared_error(real_targets, gbrt_pred)  # 计算均方误差
print(f"GBRT MSE: {gbrt_mse:.4f}")  # 打印均方误差# 定义LSTM模型
class LSTM(nn.Module):def __init__(self, input_dim, hidden_dim, num_layers):super(LSTM, self).__init__()self.lstm = nn.LSTM(input_dim, hidden_dim, num_layers, batch_first=True)  # 定义LSTM层self.fc = nn.Linear(hidden_dim, 1)  # 定义全连接层def forward(self, x):h0 = torch.zeros(num_layers, x.size(0), hidden_dim).to(x.device)  # 初始化隐藏状态c0 = torch.zeros(num_layers, x.size(0), hidden_dim).to(x.device)  # 初始化单元状态out, _ = self.lstm(x, (h0, c0))  # 前向传播out = self.fc(out[:, -1, :])  # 取最后一个时间步输出return out# 初始化LSTM模型
lstm = LSTM(input_dim=n_features * (window_size - 1), hidden_dim=hidden_dim, num_layers=num_layers)# 定义优化器和损失函数
optimizer = optim.Adam(lstm.parameters(), lr=0.001)  # 定义优化器
criterion = nn.MSELoss()  # 定义损失函数# 准备LSTM输入数据
lstm_inputs = torch.FloatTensor(mixed_inputs.reshape(-1, window_size - 1, n_features))  # 重塑输入数据
lstm_targets = torch.FloatTensor(mixed_targets)  # 转换目标数据# 训练LSTM模型
for epoch in range(num_epochs):optimizer.zero_grad()  # 清零梯度outputs = lstm(lstm_inputs)  # 前向传播loss = criterion(outputs.squeeze(), lstm_targets)  # 计算损失loss.backward()  # 反向传播optimizer.step()  # 更新参数if (epoch + 1) % 10 == 0:print(f"LSTM Epoch {epoch+1}/{num_epochs}, Loss: {loss.item():.4f}")  # 打印损失# 使用LSTM预测
with torch.no_grad():lstm_pred = lstm(torch.FloatTensor(real_inputs.reshape(-1, window_size - 1, n_features)))  # 预测
lstm_pred = lstm_pred.numpy()  # 转换为numpy数组
lstm_mse = mean_squared_error(real_targets, lstm_pred)  # 计算均方误差
print(f"LSTM MSE: {lstm_mse:.4f}")  # 打印均方误差# 可视化预测结果
plt.figure(figsize=(10, 5))  # 设置画布大小
plt.plot(real_targets[:100], label="True")  # 绘制真实值
plt.plot(gbrt_pred[:100], label="GBRT Pred")  # 绘制GBRT预测值
plt.plot(lstm_pred[:100], label="LSTM Pred")  # 绘制LSTM预测值
plt.legend()  # 显示图例
plt.title("Flood Forecasting Results")  # 设置标题
plt.show()  # 显示图像

结论

机器学习对洪水预报有着重要的作用,但极端洪水事件稀少、现场数据不足导致模型的性能并没有充分发挥出来。TimeGAN生成的数据能够保留洪水场景的复杂时空相关性,引入合成数据集也有助于提升机器学习预测精度。不过对LSTM的改进有限,TimeGAN对Transformer等深度学习模型的有效性也有待进一步探究。

不足以及展望

作者提出了本论文中的不足,作者认为TimeGAN对如LSTM等深度学习模型的改进效果有限,没有发挥出实际的作用。未建立TimeGAN损失函数与下游预报性能的关联性,缺乏了对用户自定义参数敏感性分析。
关于对论文未来的展望,作者提出后续实验可建立TimeGAN损失函数与下游预报性能的直接联系。还需要考虑将天气信息作为洪水预报模型的重要输入变量,以提供长周期预报。此外,需要进一步探索生成的洪水场景在洪水风险管理中的各种应用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/72599.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux固定IP并解决虚拟机无法ping其他电脑问题

linux固定IP并解决虚拟机无法ping其他电脑问题 1.找到网卡文件 vim /etc/sysconfig/network-scripts/ifcfg-ens33 2.编辑文件信息 BOOTPROTO 这个dhcp改为static#添加以下内容IPADDR<你的IP地址>NETMASK<子网掩码>&#xff0c;例如255.255.255.0。GATEWAY<网…

Spring实战spring-ai运行

目录 1. 配置 2 .搭建项目 3. 查看对应依赖 3.1 OpenAI 依赖 3.2 配置 OpenAI API 密钥 application.properties application.yml 4. openai实战 5. 运行和测试 6. 高级配置 示例&#xff1a;配置模型和参数 解释&#xff1a; 7. 处理异常和错误 示例&#xff1a;…

docker:配置 Docker 镜像加速器

1 镜像加速器介绍 默认情况下&#xff0c;将来从docker hub&#xff08;https://hub.docker.com/&#xff09;上下载docker镜像&#xff0c;太慢。一般都会配置镜像加速器&#xff1a; USTC&#xff1a;中科大镜像加速器&#xff08;https://docker.mirrors.ustc.edu.cn&…

[内网安全] Windows 本地认证 — NTLM 哈希和 LM 哈希

关注这个专栏的其他相关笔记&#xff1a;[内网安全] 内网渗透 - 学习手册-CSDN博客 0x01&#xff1a;SAM 文件 & Windows 本地认证流程 0x0101&#xff1a;SAM 文件简介 Windows 本地账户的登录密码是存储在系统本地的 SAM 文件中的&#xff0c;在登录 Windows 的时候&am…

算法-图-dijkstra 最短路径

理论知识 dijkstra三部曲 朴素版dijkstra 模拟过程 堆优化版dijksra 经典模版例题 Dijkstra求最短路 I 参加科学大会&#xff08;第六期模拟笔试&#xff09;--模版题 网络延迟 ref 理论知识 最短路是图论中的经典问题即&#xff1a;给出一个有向图&#xff0c;一…

Qt添加MySql数据库驱动

文章目录 一. 安装MySql二.编译mysql动态链接库 Qt版本&#xff1a;5.14.2 MySql版本&#xff1a;8.0.41 一. 安装MySql 参考这里进行安装&#xff1a;https://blog.csdn.net/qq_30150579/article/details/146042922 将mysql安装目录里的bin&#xff0c;include和lib拷贝出来…

浅论数据库聚合:合理使用LambdaQueryWrapper和XML

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、数据库聚合替代内存计算&#xff08;关键优化&#xff09;二、批量处理优化四、区域特殊处理解耦五、防御性编程增强 前言 技术认知点&#xff1a;使用 XM…

Ubuntu 22.04安装NVIDIA A30显卡驱动

一、安装前准备 1.禁用Nouveau驱动 Ubuntu默认使用开源Nouveau驱动&#xff0c;需要手动禁用&#xff1a; vim /etc/modprobe.d/blacklist-nouveau.conf # 添加以下内容&#xff1a; blacklist nouveau options nouveau modeset0 # 更新内核并重启&#xff1a; update-initr…

Docker Desktop 4.38 安装与配置全流程指南(Windows平台)

一、软件定位与特性 Docker Desktop 是容器化应用开发与部署的一体化工具&#xff0c;支持在本地环境创建、管理和运行Docker容器。4.38版本新增GPU加速支持、WSL 2性能优化和Kubernetes 1.28集群管理功能&#xff0c;适用于微服务开发、CI/CD流水线搭建等场景。 二、安装环境…

音视频入门基础:RTP专题(15)——FFmpeg源码中,获取RTP的视频信息的实现

一、引言 通过FFmpeg命令可以获取到SDP文件描述的RTP流的视频压缩编码格式、色彩格式&#xff08;像素格式&#xff09;、分辨率、帧率信息&#xff1a; ffmpeg -protocol_whitelist "file,rtp,udp" -i XXX.sdp 本文以H.264为例讲述FFmpeg到底是从哪个地方获取到这…

深度学习---卷积神经网络

一、卷积尺寸计算公式 二、池化 池化分为最大池化和平均池化 最常用的就是最大池化&#xff0c;可以认为最大池化不需要引入计算&#xff0c;而平均池化需要引出计算&#xff08;计算平均数&#xff09; 每种池化还分为Pooling和AdaptiveAvgPool Pooling(2)就是每2*2个格子…

netty中Future和ChannelHandler

netty中的Future&#xff0c;继承自 jdk中的Future&#xff0c;&#xff0c; jdk中的Future&#xff0c;很垃圾&#xff0c;只能同步阻塞获取结果&#xff0c;&#xff0c;&#xff0c; netty中的Future进行了升级&#xff0c;&#xff0c;可以addListener()异步获取结果&…

java 初学知识点总结

自己总结着玩 1.基本框架 public class HelloWorld{ public static void main(String[] args){ }//类名用大写字母开头 } 2.输入&#xff1a; (1)Scanner:可读取各种类型&#xff0c;字符串相当于cin>>; Scanner anew Scanner(System.in); Scan…

质量属性场景描述

为了精确描述软件系统的质量属性&#xff0c;通常采用质量属性场景&#xff08;Quality Attribute Scenario&#xff09;作为描述质量属性的手段。质量属性场景是一个具体的质量属性需求&#xff0c;使利益相关者与系统的交互的简短陈述。 质量属性场景是一种用于描述系统如何…

数据可携带权的多重价值与实践思考

文章目录 前言一、数据可携带权的提出与立法二、数据可携带权的多重价值1、推动数据要素市场化配置2、促进市场竞争与创新3、强化个人数据权益 三、数据可携带权的实践挑战1、数据安全与隐私保护面临风险2、接口差异导致数据迁移成本高昂3、可携带的数据范围尚存争议 数据可携带…

蓝桥每日打卡--分考场

#蓝桥#JAVA#分考场 题目描述 n个人参加某项特殊考试。 为了公平&#xff0c;要求任何两个认识的人不能分在同一个考场。 求是少需要分几个考场才能满足条件。 输入描述 输入格式&#xff1a; 第一行&#xff0c;一个整数n(1≤n≤100)&#xff0c;表示参加考试的人数。 …

RMAN备份bug-审计日志暴涨(select action from gv$session)

问题概述 /oracle 文件系统使用率过大&#xff0c;经过检查是审计日志过大,/oracle 目录 197G 审计日志占用70G&#xff0c;每6个小时产生大量审计日志&#xff0c;日志内容全是select action from gv$session &#xff0c;猜测可能跟备份有关&#xff0c; $>df -h /oracle…

在Blender中给SP分纹理组

在Blender中怎么分SP的纹理组/纹理集 其实纹理组就是材质 把同一组的材质分给同一组的模型 导入到sp里面自然就是同一个纹理组 把模型导入SP之后 就自动分好了

Nuxt:Nuxt3框架中onBeforeMount函数 和onBeforeRouteUpdate函数区别介绍 【超详细!】

提示&#xff1a;在 Nuxt3 中&#xff0c;onBeforeMount 和 onBeforeRouteUpdate 是两个不同场景下使用的钩子函数&#xff0c;分别对应 Vue 组件生命周期 和 路由导航守卫。以下是它们的详细解释和对比&#xff1a; 文章目录 一、onBeforeMount&#xff08;Vue 生命周期钩子&a…

华为 Open Gauss 数据库在 Spring Boot 中使用 Flyway

db-migration&#xff1a;Flyway、Liquibase 扩展支持达梦&#xff08;DM&#xff09;、南大通用&#xff08;GBase 8s&#xff09;、OpenGauss 等国产数据库。部分数据库直接支持 Flowable 工作流。 开源代码仓库 Github&#xff1a;https://github.com/mengweijin/db-migrat…