一、项目简介
本项目是基于PyTorch深度学习框架实现一个使用时间卷积网络(TCN,Temporal Convolutional Network)来进行风速预测的项目,该网络通过堆叠因果卷积和扩张卷积,能够捕捉时间序列依赖关系和特征,可以有效地处理时间序列数据,最后进行预测。网络的输入是风速等8个特征,输出是预测的下一天风速。【本项目的代码文件分模块整理,包含模型构建、数据划分、训练过程等模块都清晰分明】
二、TCN时间卷积网络简介
该算法于2016年由Lea等人他们在做视频动作分割的研究首先提出,CNN模型以 CNN 模型为基础,并做了如下改进:①适用序列模型:因果卷积(Causal Convolution)②记忆历史:空洞卷积/膨胀卷积(Dilated Convolution),残差模块(Residual block)。
1、因果卷积(Causal Convolution)
因果卷积是一种卷积操作,主要应用于时间序列数据或具有时序性的数据分析任务。因果卷积在卷积操作中引入了因果性,确保输出只依赖于过去的输入数据,不受未来信息的影响。(下图为因果卷积过程)
2、膨胀因果卷积(Dilated Causal Convolutions)
膨胀因果卷积(Dilated Causal Convolution)是在因果卷积的基础上引入了膨胀(Dilation)操作的一种卷积操作。它结合了因果卷积和扩张卷积(Dilated Convolution)的特性,能够增加感受野(Receptive Field)并保持因果性。(下图为膨胀因果卷积,相比于上图,以较少的计算代价实现了更大的感受野)
3、TCN整体框架
整体的TCN模型如下图所示,较深的网络结构可能会引起梯度消失等问题,该模型利用了一种类似于ResNet中的残差块的结构,这样设计的TCN结构更加的具有泛化能力。
三、实验数据集
采用的是wind_dataset.csv,本项目采用数据集中WIND、TND等八个特征参数进行预测,数据划分:以滑窗的方式进行数据划分,滑窗大小为20,输入特征为8,每次滑窗的第21天为预测的标签值。数据展示如下:
四、实验环境
平台:Window 11;语言:python3.9;编译器:Pycharm;框架:Pytorch:1.13.1
五、实验内容及部分代码展示
1、model_TCN.py 模型构建
model_TCN.py定义了项目用到的网络TCN模型,该模型由多个组件组成,包括Crop模块、TemporalCasualLayer模块、TemporalConvolutionNetwork模块和TCN模块。Crop模块用于裁剪输入张量的时间维度,去除多余的padding部分。TemporalCasualLayer模块实现了一个膨胀卷积层,由两个膨胀卷积块组成。每个膨胀卷积块包含一个带有权重归一化的卷积层、裁剪模块、ReLU激活函数和Dropout正则化。此外,还包括一个用于快捷连接的卷积层。TemporalConvolutionNetwork模块通过堆叠多个TemporalCasualLayer组成了一个完整的TCN网络。每个TemporalCasualLayer具有不同的膨胀系数,并根据输入和输出通道的数量进行设置。TCN模块封装了TemporalConvolutionNetwork,并添加了一个线性层用于最终的预测。在前向传播中,先经过TCN网络,然后将输出的最后一个时间步传入线性层,并通过ReLU激活函数进行非线性变换。通过以上组件的组合,该TCN模型可以用于时间序列建模任务,并在最后输出预测结果。
import torch.nn as nn
from torch.nn.utils import weight_norm
#用于裁剪输入张量的时间维度,去除多余的 padding 部分。
class Crop(nn.Module):
def __init__(self, crop_size):
super(Crop, self).__init__()
self.crop_size = crop_size
def forward(self, x):
#裁剪张量以去除额外的填充
return x[:, :, :-self.crop_size].contiguous()
#实现了一个膨胀卷积层,由两个膨胀卷积块组成。每个膨胀卷积块包含一个带有权重归一化的卷积层、裁剪模块、ReLU激活函数和 Dropout 正则化。此外,还包括了一个用于快捷连接的卷积层
class TemporalCasualLayer(nn.Module):
def __init__(self, n_inputs, n_outputs, kernel_size, stride, dilation, dropout=0.2):
super(TemporalCasualLayer, self).__init__()
padding = (kernel_size - 1) * dilation
conv_params = {
'kernel_size': kernel_size,
'stride': stride,
'padding': padding,
'dilation': dilation
}
self.conv1 = weight_norm(nn.Conv1d(n_inputs, n_outputs, **conv_params))
self.crop1 = Crop(padding)
self.relu1 = nn.ReLU()
self.dropout1 = nn.Dropout(dropout)
self.conv2 = weight_norm(nn.Conv1d(n_outputs, n_outputs, **conv_params))
self.crop2 = Crop(padding)
self.relu2 = nn.ReLU()
self.dropout2 = nn.Dropout(dropout)
self.net = nn.Sequential(self.conv1, self.crop1, self.relu1, self.dropout1,
self.conv2, self.crop2, self.relu2, self.dropout2)
#快捷连接
self.bias = nn.Conv1d(n_inputs, n_outputs, 1) if n_inputs != n_outputs else None
self.relu = nn.ReLU()
def forward(self, x):
# 应用因果卷积和快捷连接
y = self.net(x)
b = x if self.bias is None else self.bias(x)
return self.relu(y + b)
#通过堆叠多个 TemporalCasualLayer 组成了一个完整的 TCN 网络。每个 TemporalCasualLayer 具有不同的膨胀系数,并根据输入和输出通道的数量进行设置。
class TemporalConvolutionNetwork(nn.Module):
def __init__(self, num_inputs, num_channels, kernel_size=2, dropout=0.2):
super(TemporalConvolutionNetwork, self).__init__()
layers = []
num_levels = len(num_channels)
tcl_param = {
'kernel_size': kernel_size,
'stride': 1,
'dropout': dropout
}
for i in range(num_levels):
dilation = 2 ** i
in_ch = num_inputs if i == 0 else num_channels[i - 1]
out_ch = num_channels[i]
tcl_param['dilation'] = dilation
tcl = TemporalCasualLayer(in_ch, out_ch, **tcl_param)
# tcl = self.relu(tcl)
layers.append(tcl)
self.network = nn.Sequential(*layers)
def forward(self, x):
return self.network(x)
#封装了 TemporalConvolutionNetwork,并添加了一个线性层用于最终的预测。在前向传播中,先经过 TCN 网络,然后将输出的最后一个时间步传入线性层,并通过 ReLU 激活函数进行非线性变换。
class TCN(nn.Module):
def __init__(self, input_size, output_size, num_channels, kernel_size, dropout):
super(TCN, self).__init__()
self.tcn = TemporalConvolutionNetwork(input_size, num_channels, kernel_size=kernel_size, dropout=dropout)
self.linear = nn.Linear(num_channels[-1], output_size)
self.relu = nn.ReLU()
def forward(self, x):
# 应用TCN和线性层,然后使用ReLU激活函数
y = self.tcn(x) # [N,C_out,L_out=L_in]
return self.relu(self.linear(y[:, :, -1]))
2、train.py 训练通用模板
训练过程集成到fit函数里面,包含测试集训练过程和验证集计算过程,是项目训练过程的通用代码,其他项目也可以在它的基础上修改后使用。
3、Config.py 参数定义
config中定义了项目的基本参数,可以在里面修改训练参数。
4、DataSplit.py 数据划分
DataSplit.py 是实现数据划分的函数,通过滑动窗口,将每个窗口大小的数据作为训练数据,将其后面一个数据作为预测结果,再进行划分训练数据和标签,最后分成训练集和验证集。
5、test_wind_TCN_run.py 训练文件
该py文件实现整体训练流程并做绘图操作。依次实现加载数据、数据标准化、取出WIND数据、划分训练集测试集、数据转化为Tensor、形成数据更迭器、载入模型、定义损失、定义优化器、开始训练、损失可视化、显示预测结果。
6、test_pth.py 模型训练后的测试文件
采用模型训练完成后的pth对数据进行预测,可以展示模型预测效果,前面的处理过程类似test_wind_TCN_run.py所示。
7、loss_draw.py 模型训练后的loss绘图
将训练后产生并收集的loss.csv展示出来,也就是损失图,红框可调展示范围。
8、predict_pth.py 用某20天数据预测后1天的风速数值
用某前20天的八个风速特征数据预测后1天风速并绘图和可视化具体的数值
六、实验结果及分析
1、训练过程
这是训练过程中的可视化,会输出train_loss和test_loss
2、loss损失图
该损失是训练了200个epoch的损失图:
3、test_pth.py预测效果展示(预测图)
train-训练epoch=200后的风速预测效果train如下,展示前两百天的预测效果:(红色是真实的,蓝色是预测的)
test-训练epoch=200后的风速预测效果如下(使用pth参数文件进行测试预测),展示前两百天的预测效果):红色是真实的,蓝色是预测的)
4、predict_pth.py预测效果展示(预测具体的某50天)
使用如下图所示的前20天风速,预测后1天的风速值
七、总结及资源
若有朋友需要可运行的源码和数据集,可以guan注【科研小条】gong众号,回复【TCN多特征风速预测】,即可获得。