首页 > 其他分享 >基于TCN-Transformer-KAN混合模型实现电力负荷时序预测——Kolmogorov-Arnold Network(KAN 2.0)模型融合详解(PyTorch版)

基于TCN-Transformer-KAN混合模型实现电力负荷时序预测——Kolmogorov-Arnold Network(KAN 2.0)模型融合详解(PyTorch版)

时间:2024-12-01 09:05:17浏览次数:6  
标签:MSELoss train 模型 KAN Train MAELoss 2.0 self size

在这里插入图片描述

前言

系列专栏:【深度学习:算法项目实战】✨︎
涉及医疗健康、财经金融、商业零售、食品饮料、运动健身、交通运输、环境科学、社交媒体以及文本和图像处理等诸多领域,讨论了各种复杂的深度神经网络思想,如卷积神经网络、循环神经网络、生成对抗网络、门控循环单元、长短期记忆、自然语言处理、深度强化学习、大型语言模型和迁移学习。

在当今数字化与智能化快速发展的时代,电力系统的高效稳定运行对于社会的各个方面都起着至关重要的作用。负荷预测作为一项关键环节,对于保障电力供需平衡、优化资源配置具有至关重要的作用。准确的电力负荷预测有助于降低发电成本、减少能源浪费,并提升电力系统的可靠性与灵活性。

近年来,深度学习技术在时间序列预测领域取得了显著进展,尤其是TCN(Temporal Convolutional Networks,时间卷积网络)、Transformer以及KAN(Kolmogorov-Arnold Networks,柯尔莫哥洛夫-阿诺德网络)等模型的提出,为负荷预测提供了新的思路和方法。TCN作为一种专门为时间序列数据设计的卷积神经网络,通过膨胀卷积有效捕捉长程依赖关系,并具备良好的并行化能力;Transformer则凭借其自注意力机制,在自然语言处理领域取得巨大成功后,也被广泛应用于时间序列数据的全局特征提取;KAN则基于Kolmogorov-Arnold表示定理,通过可学习的激活函数逼近复杂函数关系,展现出较高的准确性和可解释性。

鉴于上述模型各自的优势,本文提出了一种基于TCN-Transformer-KAN混合模型的电力负荷时序预测方法,旨在通过结合三者的长处,进一步提高负荷预测的精度和效率。具体而言,TCN负责提取时间序列数据的局部特征和短期依赖关系,Transformer捕捉全局特征和长程依赖关系,而KAN则利用其强大的函数逼近能力处理复杂的非线性关系。三者相辅相成,共同提升模型的预测性能。

本文详细阐述了TCN-Transformer-KAN混合模型的构建过程,包括数据预处理、模型结构设计、训练与优化策略等。通过实际电力负荷数据的实验验证,展示了该混合模型在提高预测精度和效率方面的显著效果。有望为智能电网的规划与运营提供有力支持。我们相信,随着深度学习技术的不断发展,该模型将在更多领域展现出其独特的优势和广泛的应用前景。

目录

1. 数据集介绍

本文用到的数据集是ETTh1.csv,ETTh1数据集是电力变压器数据集(ETDataset)的一部分,旨在用于长序列时间序列预测问题的研究。该数据集收集了中国两个不同县两年的数据,以预测特定地区的电力需求情况。


import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import seaborn as sns

from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_absolute_error, \
                            mean_absolute_percentage_error, \
                            mean_squared_error, root_mean_squared_error, \
                            r2_score

import torch
import torch.nn as nn
from torch.nn.utils.parametrizations import weight_norm
from torch.utils.data import DataLoader, TensorDataset, Dataset
from torchinfo import summary
from kan import KAN

np.random.seed(0)
torch.manual_seed(0)
data = pd.read_csv('ETTh1.csv')
data.head(5).style.background_gradient()

数据集

2. 数据预处理

在数据处理和分析过程中,经常需要将日期和时间的字符串表示转换为 Pandas 的 Timestamp 对象,以便进行后续的时间序列分析、日期筛选、时间差计算等操作。pandas.to_datetime 将数据转换为 datetime 类型。

print(type(data['OT'].iloc[0]), type(data['date'].iloc[0]))
# Convert the data type of timestamp column to datatime format

data['date'] = pd.to_datetime(data['date'])
print(type(data['OT'].iloc[0]), type(data['date'].iloc[0]))

data = data.set_index('date').sort_index()
<class 'numpy.float64'> <class 'str'>
<class 'numpy.float64'> <class 'pandas._libs.tslibs.timestamps.Timestamp'>

3. 数据可视化

时序数据往往包含大量的时间点记录,直接查看原始数据可能既耗时又难以捕捉关键信息。通过数据可视化,可以能够迅速把握数据的整体趋势和波动情况。接下来我们观察一下OT列的特征趋势。

sns.set_style('whitegrid')
# plt.style.use('seaborn-v0_8-whitegrid')
fig, ax = plt.subplots(figsize=(10, 6))

# 绘制数据
ax.plot(data['OT'], color='darkorange' ,label='Trend')

# 设置x轴为时间轴,并显示具体日期
locator = mdates.AutoDateLocator(minticks=8, maxticks=12)  # 自动定位刻度
formatter = mdates.DateFormatter('%Y-%m-%d')  # 自定义刻度标签格式
ax.xaxis.set_major_locator(locator)
ax.xaxis.set_major_formatter(formatter)

# 设置标题
plt.title('OT  Trend', fontdict={'family': 'Times New Roman', 'fontsize': 15, 'color':'black'})
plt.xticks(rotation=45) # 旋转刻度标签以提高可读性
plt.ylabel('Temp', fontdict={'family': 'Times New Roman', 'fontsize': 14})
plt.legend(loc="upper right", prop={'family': 'Times New Roman'})
plt.show()

请添加图片描述

4. 特征工程

特征工程有助于从现有特征中派生出一些有价值的特征。这些额外的功能有时有助于显著提高模型的性能,当然也有助于更深入地了解数据。这里我们选择 OT 单个特征来训练模型。。。通过特征相关性其实我们可以看出 OT 与其他特征相关性很低。

values = data['OT'].values.reshape(-1, 1)

reshape 方法用于改变数组的形状。第一个参数 -1 表示自动推断该维度的大小,使得数组在保持总元素数量不变的情况下,根据第二个参数的要求进行重塑。第二个参数 1 指定了新数组的第二维度为 1。举例说明,如果原始的 data 是一个一维数组 [1, 2, 3, 4],执行 data.reshape(-1, 1) 后,data 将变为一个二维数组 [[1], [2], [3], [4]]。如果原始的 data 是一个二维数组,比如 [[1, 2], [3, 4]] ,执行该操作后会将其转换为一个二维数组,其中每个元素都被转换为一个包含单个元素的列表,即 [[1], [2], [3], [4]]

4.1 特征缩放(归一化)

# 创建 MinMaxScaler实例,对特征进行拟合和变换,生成NumPy数组
scaler = MinMaxScaler()
values_scaled = scaler.fit_transform(values)
print(values_scaled.shape)

在 scikit-learn 库中,MinMaxScaler() 函数将数据集中的每个特征[列]进行线性变换,使得特征值映射到一个指定的区间,通常是 [0, 1]。对于特征中的每个 x x x 值,转换公式为 x n e w = x − x m i n x m a x − x m i n x_{new}=\frac{x-x_{min}} {x_{max}-x_{min}} xnew​=xmax​−xmin​x−xmin​​,其中 x m i n x_{min} xmin​是该特征的最小值, x m a x x_{max} xmax​是该特征的最大值。这种缩放方法可以帮助改善算法的收敛速度和性能,特别是在特征尺度差异较大的情况下。

4.2 构建监督学习数据

在时间序列预测中,我们将时间序列数据转换为监督学习格式,可以方便地应用各种机器学习模型进行预测。

time_steps = 10
X_list = []
y_list = []

for i in range(len(values_scaled) - time_steps):
    X_list.append(values_scaled[i:i+time_steps])
    y_list.append(values_scaled[i+time_steps])

X = np.array(X_list) # [samples, time_steps, num_features]
y = np.array(y_list) # [target]

上述代码的目的是进行时间序列数据的预处理,将原始的时间序列数据转换为适合机器学习模型输入的监督学习数据格式。time_steps:表示每个样本中包含的时间步数,它决定了模型在预测时考虑的历史数据长度。X_list:用于存储分割后的特征数据样本的列表。y_list:用于存储每个特征数据样本对应的目标值的列表。

  • for i in range(len(values_scaled) - time_steps):使用 for 循环遍历 values_scaled,但会在倒数第 time_steps 个元素处停止,因为后面不足 time_steps 个数据来构建特征。
  • X_list.append(values_scaled[i:i + time_steps]):对于每个索引i,从标准化后的时间序列数据values_scaled中提取从ii + time_steps行的数据。例如,如果time_steps = 10,当i = 0时,它会选择第 0 \text{0} 0 行到第 9 \text{9} 9 行的数据。
  • y_list.append(values_scaled[i +time_steps]):这里是提取目标值。对于每个索引i,选择i + time_steps行的元素作为目标值。例如,当i = 0time_steps = 10时,会选择第 10 \text{10} 10 行的元素作为目标值。这个目标值被添加到y_list中。

4.3 数据集划分

train_test_split 函数将数组或矩阵随机分成训练子集和测试子集。

X_temp, X_test, y_temp, y_test = train_test_split(X, y, test_size=0.2, random_state=42, shuffle=False)
X_train, X_val, y_train, y_val = train_test_split(X_temp, y_temp, test_size=0.25, random_state=42, shuffle=False)  # 0.25 是相对于剩余 80% 数据的比例
print(X_train.shape, X_val.shape, X_test.shape, y_train.shape, y_val.shape, y_test.shape)
(10446, 10, 1) (3482, 10, 1) (3482, 10, 1) (10446, 1) (3482, 1) (3482, 1)

以上代码中 random_state=45 设置了随机种子,以确保每次运行代码时分割结果的一致性。shuffle=False 表示在分割数据时不进行随机打乱。如果设置为True(默认值),则会在分割之前对数据进行随机打乱,这样可以增加数据的随机性,但时间序列数据具有连续性,所以设置为False

4.4 数据加载器

class DataHandler(Dataset):
    def __init__(self, batch_size):
        self.X_train_tensor = torch.tensor(X_train, dtype=torch.float32)
        self.X_val_tensor = torch.tensor(X_val, dtype=torch.float32)
        self.y_train_tensor = torch.tensor(y_train, dtype=torch.float32)
        self.y_val_tensor = torch.tensor(y_val, dtype=torch.float32)
        self.batch_size = batch_size
        
    def __len__(self):
        return len(self.X_train_tensor)

    def __getitem__(self, idx, dataset_type='train'):
        if dataset_type == 'train':
            sample = self.X_train_tensor[idx]
            labels = self.y_train_tensor[idx]
        elif dataset_type == 'val':
            sample = self.X_val_tensor[idx]
            labels = self.y_val_tensor[idx]
        return sample, labels
        
    def train_loader(self):
        train_dataset = TensorDataset(self.X_train_tensor, self.y_train_tensor)
        return DataLoader(train_dataset, batch_size=self.batch_size, shuffle=True)

    def valid_loader(self):
        valid_dataset = TensorDataset(self.X_val_tensor, self.y_val_tensor)
        return DataLoader(valid_dataset, batch_size=self.batch_size, shuffle=False)

在上述代码中,定义了一个名为 DataHandler 的类,它继承自 torch.utils.data.Dataset
__init__ 方法用于接收数据和标签。__len__ 方法返回数据集的长度。__getitem__ 方法根据给定的索引 idx 返回相应的数据样本和标签。

batch_size= 256
data_handler = DataHandler(batch_size=batch_size)
train_loader = data_handler.train_loader()
valid_loader = data_handler.valid_loader()

在上述代码中,创建了一个数据处理对象 data_handler,并通过该对象生成训练集数据加载器 train_loader 和验证集数据加载器valid_loader。通过这种方式,可以方便地管理和加载训练集和验证集数据,为深度学习模型的训练和评估提供了数据支持。


5. 构建时序模型(TSF)

5.1 定义TCN神经网络

TemporalConvNet,或称时间卷积网络(Temporal Convolutional Networks, TCN),是一种专门用于处理时间序列数据的深度神经网络架构。1

class Chomp1d(nn.Module):
    def __init__(self, chomp_size):
        super(Chomp1d, self).__init__()
        self.chomp_size = chomp_size

    def forward(self, x):
        return x[:, :, :-self.chomp_size].contiguous()


class TemporalBlock(nn.Module):
    def __init__(self, n_inputs, n_outputs, kernel_size, stride, dilation, padding, dropout=0.2):
        super(TemporalBlock, self).__init__()
        self.conv1 = weight_norm(nn.Conv1d(n_inputs, n_outputs, kernel_size,
                                           stride=stride, padding=padding, dilation=dilation))
        self.chomp1 = Chomp1d(padding)
        self.bn1 = nn.BatchNorm1d(n_outputs)
        self.relu1 = nn.ReLU()
        self.dropout1 = nn.Dropout(dropout)

        self.conv2 = weight_norm(nn.Conv1d(n_outputs, n_outputs, kernel_size,
                                           stride=stride, padding=padding, dilation=dilation))
        self.chomp2 = Chomp1d(padding)
        self.bn2 = nn.BatchNorm1d(n_outputs)
        self.relu2 = nn.ReLU()
        self.dropout2 = nn.Dropout(dropout)

        self.net = nn.Sequential(self.conv1, self.chomp1, self.bn1, self.relu1, self.dropout1,
                                 self.conv2, self.chomp2, self.bn2, self.relu2, self.dropout2)
        self.downsample = nn.Conv1d(n_inputs, n_outputs, 1) if n_inputs != n_outputs else None
        self.relu = nn.ReLU()
        self.init_weights()

    def init_weights(self):
        self.conv1.weight.data.normal_(0, 0.01)
        self.conv2.weight.data.normal_(0, 0.01)
        if self.downsample is not None:
            self.downsample.weight.data.normal_(0, 0.01)

    def forward(self, x):
        out = self.net(x)
        res = x if self.downsample is None else self.downsample(x)
        return self.relu(out + res)


class TemporalConvNet(nn.Module):
    def __init__(self, num_inputs, num_channels, kernel_size=2, dropout=0.2):
        super(TemporalConvNet, self).__init__()
        layers = []
        num_levels = len(num_channels)
        for i in range(num_levels):
            dilation_size = 2 ** i
            in_channels = num_inputs if i == 0 else num_channels[i-1]
            out_channels = num_channels[i]
            layers += [TemporalBlock(in_channels, out_channels, kernel_size, stride=1, dilation=dilation_size,
                                     padding=(kernel_size-1) * dilation_size, dropout=dropout)]

        self.network = nn.Sequential(*layers)

    def forward(self, x):
        return self.network(x)

依据原作者的代码,博主加入了 nn.BatchNorm1d 层,nn.BatchNorm1d 是PyTorch框架中的一个模块,它用于对一维数据(通常是时间序列数据或全连接层的输出)进行批归一化。批归一化是一种在神经网络训练过程中常用的技术,它有助于加速训练过程,提高模型的稳定性和性能。2

5.2 定义TCN-Transformer-KAN网络结构

‌TCN-Transformer-KAN ‌\text{TCN-Transformer-KAN} ‌TCN-Transformer-KAN 网络结构‌是一个融合了时间卷积网络 ‌Temporal Convolutional Network, TCN ‌\text{Temporal Convolutional Network, TCN} ‌Temporal Convolutional Network, TCN ‌Transformer ‌\text{Transformer} ‌Transformer ‌Kolmogorov-Arnold Network, KAN ‌\text{Kolmogorov-Arnold Network, KAN} ‌Kolmogorov-Arnold Network, KAN 3 的复合神经网络结构。这种结构旨在结合各自组件的优势,以提高神经网络的性能、可解释性和适应性。以下是对该网络结构的详细定义:

class TCN_Transformer_KAN(nn.Module):
    def __init__(self, input_size, output_size, num_channels, hidden_dim, kernel_size, transformer_heads, transformer_layers ,dropout):
        super(TCN_Transformer_KAN, self).__init__()
        self.tcn = TemporalConvNet(input_size, num_channels, kernel_size = kernel_size, dropout = dropout)
        transformer_encoder_layer = nn.TransformerEncoderLayer(d_model=hidden_dim, nhead=transformer_heads, dim_feedforward=hidden_dim * 2, dropout=dropout, batch_first=True)
        self.transformer_encoder = nn.TransformerEncoder(transformer_encoder_layer, num_layers=transformer_layers)
        self.kan = KAN([hidden_dim, output_size])
 
    def forward(self, x):
        x = x.permute(0, 2, 1) # 调整输入形状 TemporalConvNet 的期望输入 [N, C_in, L_in]
        x = self.tcn(x)  # [N, C_out, L_out=L_in]
        x = x.permute(0, 2, 1) # 调整输出形状 [N, L_out, C_out]

        x = self.transformer_encoder(x)
        
        x = x[:, -1, :]  # 最后一个时间步的输出 [N, C_out]
        return self.kan(x)  

上述代码self.kan = KAN([hidden_dim, output_size]) :创建了一个 KAN (从 from kan import KAN 导入)实例,它接收一个包含两个元素的列表作为参数,用于将经过前面网络处理后的特征维度从 hidden_dim 转换为最终期望的输出维度 output_size 4

5.3 实例化模型、损失函数和优化器

params = {
    # 'input_size',C_in
    'input_size': 1,
    # 单步,预测未来一个时刻
    'output_size': 1,
    'num_channels': [128] * 3,
    'kernel_size': 4,
    'hidden_dim': 128,
    'transformer_heads': 8,
    'transformer_layers': 3,
    'dropout': .5,
}
model = TCN_Transformer_KAN(**params)
criterion_mse = nn.MSELoss()  # 定义均方误差损失函数
criterion_mae = nn.L1Loss()  # 定义平均绝对误差损失
optimizer = torch.optim.Adam(model.parameters(), lr=0.001) # 定义优化器

5.4 模型概要

# batch_size, seq_len, input_size(in_channels)
summary(model, (batch_size, time_steps, num_features)) 
==============================================================================================================
Layer (type:depth-idx)                                       Output Shape              Param #
==============================================================================================================
TCN_Transformer_KAN                                          [256, 1]                  --
├─TemporalConvNet: 1-1                                       [256, 128, 10]            --
│    └─Sequential: 2-1                                       [256, 128, 10]            --
│    │    └─TemporalBlock: 3-1                               [256, 128, 10]            67,328
│    │    └─TemporalBlock: 3-2                               [256, 128, 10]            132,096
│    │    └─TemporalBlock: 3-3                               [256, 128, 10]            132,096
├─TransformerEncoder: 1-2                                    [256, 10, 128]            --
│    └─ModuleList: 2-2                                       --                        --
│    │    └─TransformerEncoderLayer: 3-4                     [256, 10, 128]            132,480
│    │    └─TransformerEncoderLayer: 3-5                     [256, 10, 128]            132,480
│    │    └─TransformerEncoderLayer: 3-6                     [256, 10, 128]            132,480
├─MultKAN: 1-3                                               [256, 1]                  4
│    └─ModuleList: 2-3                                       --                        --
│    │    └─KANLayer: 3-7                                    [256, 1]                  2,432
│    └─SiLU: 2-4                                             [256, 128]                --
│    └─ModuleList: 2-5                                       --                        --
│    │    └─Symbolic_KANLayer: 3-8                           [256, 1]                  640
==============================================================================================================
Total params: 732,036
Trainable params: 730,496
Non-trainable params: 1,540
Total mult-adds (Units.MEGABYTES): 52.07
==============================================================================================================
Input size (MB): 0.01
Forward/backward pass size (MB): 57.67
Params size (MB): 0.81
Estimated Total Size (MB): 58.49
==============================================================================================================

6. 模型训练与可视化

6.1 定义训练与评估函数

在模型训练之前,我们通常需先定义 train 函数来执行模型训练过程

def train(model, iterator, optimizer):
    epoch_loss_mse = 0
    epoch_loss_mae = 0

    model.train()  # 确保模型处于训练模式
    for batch in iterator:
        optimizer.zero_grad()  # 清空梯度
        inputs, targets = batch  # 获取输入和目标值
        outputs = model(inputs)  # 前向传播

        loss_mse = criterion_mse(outputs, targets)  # 计算损失
        loss_mae = criterion_mae(outputs, targets)

        combined_loss = loss_mse + loss_mae  # 可以根据需要调整两者的权重

        combined_loss.backward()
        optimizer.step()

        epoch_loss_mse += loss_mse.item()  # 累计损失
        epoch_loss_mae += loss_mae.item()

    average_loss_mse = epoch_loss_mse / len(iterator)  # 计算平均损失
    average_loss_mae = epoch_loss_mae / len(iterator)

    return average_loss_mse, average_loss_mae

上述代码定义了一个名为 train 的函数,用于训练给定的模型。它接收模型、数据迭代器、优化器作为参数,并返回训练过程中的平均损失。


def evaluate(model, iterator):
    epoch_loss_mse = 0
    epoch_loss_mae = 0

    model.eval()  # 将模型设置为评估模式,例如关闭 Dropout 等
    with torch.no_grad():  # 不需要计算梯度
        for batch in iterator:
            inputs, targets = batch
            outputs = model(inputs)  # 前向传播

            loss_mse = criterion_mse(outputs, targets)  # 计算损失
            loss_mae = criterion_mae(outputs, targets)

            epoch_loss_mse += loss_mse.item()  # 累计损失
            epoch_loss_mae += loss_mae.item()

    return epoch_loss_mse / len(iterator), epoch_loss_mae / len(iterator)

上述代码定义了一个名为 evaluate 的函数,用于评估给定模型在给定数据迭代器上的性能。它接收模型、数据迭代器作为参数,并返回评估过程中的平均损失。这个函数通常在模型训练的过程中定期被调用,以监控模型在验证集或测试集上的性能。通过评估模型的性能,可以了解模型的泛化能力和训练的进展情况。


6.2 模型训练与损失记录

epoch = 500
train_mselosses = []
valid_mselosses = []
train_maelosses = []
valid_maelosses = []

for epoch in range(epoch):
    train_loss_mse, train_loss_mae = train(model, train_loader, optimizer)
    valid_loss_mse, valid_loss_mae = evaluate(model, valid_loader)

    train_mselosses.append(train_loss_mse)
    valid_mselosses.append(valid_loss_mse)
    train_maelosses.append(train_loss_mae)
    valid_maelosses.append(valid_loss_mae)

    print(f'Epoch: {epoch + 1:02}, Train MSELoss: {train_loss_mse:.5f}, Train MAELoss: {train_loss_mae:.3f}, Val. MSELoss: {valid_loss_mse:.5f}, Val. MAELoss: {valid_loss_mae:.3f}')
Epoch: 01, Train MSELoss: 0.05760, Train MAELoss: 0.162, Val. MSELoss: 0.01492, Val. MAELoss: 0.114
Epoch: 02, Train MSELoss: 0.00706, Train MAELoss: 0.066, Val. MSELoss: 0.00140, Val. MAELoss: 0.028
Epoch: 03, Train MSELoss: 0.00532, Train MAELoss: 0.057, Val. MSELoss: 0.00640, Val. MAELoss: 0.074
Epoch: 04, Train MSELoss: 0.00448, Train MAELoss: 0.052, Val. MSELoss: 0.00098, Val. MAELoss: 0.023
Epoch: 05, Train MSELoss: 0.00383, Train MAELoss: 0.048, Val. MSELoss: 0.00219, Val. MAELoss: 0.039
Epoch: 06, Train MSELoss: 0.00352, Train MAELoss: 0.046, Val. MSELoss: 0.00496, Val. MAELoss: 0.066
Epoch: 07, Train MSELoss: 0.00332, Train MAELoss: 0.045, Val. MSELoss: 0.00100, Val. MAELoss: 0.025
Epoch: 08, Train MSELoss: 0.00325, Train MAELoss: 0.044, Val. MSELoss: 0.00197, Val. MAELoss: 0.037
Epoch: 09, Train MSELoss: 0.00270, Train MAELoss: 0.040, Val. MSELoss: 0.00279, Val. MAELoss: 0.048
Epoch: 10, Train MSELoss: 0.00268, Train MAELoss: 0.040, Val. MSELoss: 0.00059, Val. MAELoss: 0.018
Epoch: 491, Train MSELoss: 0.00048, Train MAELoss: 0.015, Val. MSELoss: 0.00030, Val. MAELoss: 0.012
Epoch: 492, Train MSELoss: 0.00046, Train MAELoss: 0.015, Val. MSELoss: 0.00032, Val. MAELoss: 0.013
Epoch: 493, Train MSELoss: 0.00046, Train MAELoss: 0.015, Val. MSELoss: 0.00034, Val. MAELoss: 0.014
Epoch: 494, Train MSELoss: 0.00048, Train MAELoss: 0.015, Val. MSELoss: 0.00049, Val. MAELoss: 0.016
Epoch: 495, Train MSELoss: 0.00047, Train MAELoss: 0.015, Val. MSELoss: 0.00025, Val. MAELoss: 0.011
Epoch: 496, Train MSELoss: 0.00047, Train MAELoss: 0.015, Val. MSELoss: 0.00025, Val. MAELoss: 0.011
Epoch: 497, Train MSELoss: 0.00047, Train MAELoss: 0.015, Val. MSELoss: 0.00025, Val. MAELoss: 0.012
Epoch: 498, Train MSELoss: 0.00046, Train MAELoss: 0.015, Val. MSELoss: 0.00023, Val. MAELoss: 0.011
Epoch: 499, Train MSELoss: 0.00046, Train MAELoss: 0.015, Val. MSELoss: 0.00021, Val. MAELoss: 0.011
Epoch: 500, Train MSELoss: 0.00046, Train MAELoss: 0.015, Val. MSELoss: 0.00021, Val. MAELoss: 0.010

上述代码主要进行了模型的训练和评估过程,并记录了每个 epoch 的训练和验证集上的均方误差损失(MSE Loss)和平均绝对误差损失(MAE Loss)。这里仅展示了首尾各10个epoch,我们可以清晰的看到loss一直在降低,还有下降的趋势。

6.3 绘制损失曲线

fig, ax = plt.subplots(ncols=1, nrows=2, figsize=(10, 12))

# MSE 损失曲线
ax[0].plot(train_mselosses, label='Train MSELoss')
ax[0].plot(valid_mselosses, label='Valid MSELoss')
ax[0].set_title('MSE Loss Curve', fontdict={'family': 'Times New Roman', 'fontsize': 16, 'fontweight': 'bold', 'color': 'blue'})
ax[0].set_xlabel('Iterations', fontdict={'family': 'Times New Roman', 'fontsize': 14})
ax[0].set_ylabel('MSE', fontdict={'family': 'Times New Roman', 'fontsize': 14})
ax[0].legend(prop={'family': 'Times New Roman'})
ax[0].set_yscale("log")  # 如果需要对数刻度

# MAE 损失曲线
ax[1].plot(train_maelosses, label='Train MAELoss')
ax[1].plot(valid_maelosses, label='Valid MAELoss')
ax[1].set_title('MAE Loss Curve', fontdict={'family': 'Times New Roman', 'fontsize': 16, 'fontweight': 'bold', 'color': 'blue'})
ax[1].set_xlabel('Iterations', fontdict={'family': 'Times New Roman', 'fontsize': 14})
ax[1].set_ylabel('MAE', fontdict={'family': 'Times New Roman', 'fontsize': 14})
ax[1].legend(prop={'family': 'Times New Roman'})
ax[1].set_yscale("log")  # 如果需要对数刻度

plt.tight_layout()
plt.show()

损失记录

7. 模型评估与可视化

7.1 构建预测函数

定义预测函数 prediction 方便调用

# 定义 prediction函数
def prediction(model, iterator): 
    all_targets = []
    all_predictions = []

    model.eval()
    with torch.no_grad():
        for batch in iterator:
            inputs, targets = batch
            predictions = model(inputs)
            
            all_targets.extend(targets.numpy())
            all_predictions.extend(predictions.numpy())
    return all_targets, all_predictions

这段代码定义了一个名为 prediction 的函数,其主要目的是使用给定的模型对输入数据进行预测,并收集所有的目标值和预测值。

7.2 验证集预测

# 模型预测
y_true, y_pred = prediction(model, valid_loader)
y_true_denormalized = scaler.inverse_transform(y_true).ravel()
y_pred_denormalized = scaler.inverse_transform(y_pred).ravel()
# 计算标准误差 (Standard Deviation)
standard_dev = np.std(y_pred_denormalized, ddof=1) / np.sqrt(len(y_pred_denormalized))

# 根据正态分布的特性,计算z分数
# 对于95%的置信水平,z分数约为1.96(这是基于标准正态分布的双侧区间)
z_score = 1.96

# 计算置信区间的上下界
lower_bound = y_pred_denormalized - z_score * standard_dev
upper_bound = y_pred_denormalized + z_score * standard_dev
plt.figure(figsize=(10,6))

x_coords = np.arange(len(y_pred_denormalized))
plt.plot(y_true_denormalized, label='Actual Values')
plt.plot(y_pred_denormalized, label='Predicted Values')
plt.fill_between(x=x_coords, 
                 y1=lower_bound, y2=upper_bound,
                 color='pink', alpha=0.3, label='Confidence Interval')

plt.title('Comparison of validation set prediction results', 
          fontdict={'family': 'Times New Roman', 
          'fontsize': 16, 'fontweight': 'bold', 'color': 'blue'})
plt.ylabel('Temp', fontdict={'family': 'Times New Roman', 'fontsize': 14})
plt.legend(prop={'family': 'Times New Roman'})
plt.show()

验证集预测

7.3 回归拟合图

使用 regplot() 函数绘制数据图,拟合预测值与真实值的线性回归图。

plt.figure(figsize=(5, 5), dpi=100)
sns.regplot(x=y_true_denormalized, y=y_pred_denormalized, scatter=True, marker="*", color='orange',line_kws={'color': 'red'})
plt.show()

回归拟合图

7.4 评估指标

以下代码使用了一些常见的评估指标:平均绝对误差(MAE)、平均绝对百分比误差(MAPE)、均方误差(MSE)、均方根误差(RMSE)和决定系数(R²)来衡量模型预测的性能。这里我们将通过调用 sklearn.metrics 模块中的 mean_absolute_error mean_absolute_percentage_error mean_squared_error root_mean_squared_error r2_score 函数来对模型的预测效果进行评估。

mae = mean_absolute_error(targets, predictions)
print(f"MAE: {mae:.4f}")

mape = mean_absolute_percentage_error(targets, predictions)
print(f"MAPE: {mape * 100:.4f}%")

mse = mean_squared_error(targets, predictions)
print(f"MSE: {mse:.4f}")

rmse = root_mean_squared_error(targets, predictions)
print(f"RMSE: {rmse:.4f}")

r2 = r2_score(targets, predictions)
print(f"R²: {r2:.4f}")
MAE: 0.0105
MAPE: 6.1967%
MSE: 0.0002
RMSE: 0.0147
R²: 0.9719

参考链接


  1. An Empirical Evaluation of Generic Convolutional and Recurrent Networks for Sequence Modeling ↩︎

  2. TCN Source Code ↩︎

  3. KAN 2.0: Kolmogorov-Arnold Networks Meet Science ↩︎

  4. KAN Source Code ↩︎

标签:MSELoss,train,模型,KAN,Train,MAELoss,2.0,self,size
From: https://blog.csdn.net/m0_63287589/article/details/144013746

相关文章

  • 1DCNN-2DResNet并行故障诊断模型
    往期精彩内容:Python-凯斯西储大学(CWRU)轴承数据解读与分类处理Pytorch-LSTM轴承故障一维信号分类(一)-CSDN博客Pytorch-CNN轴承故障一维信号分类(二)-CSDN博客Pytorch-Transformer轴承故障一维信号分类(三)-CSDN博客三十多个开源数据集|故障诊断再也不用担心数据集了!P......
  • 独家原创 | 超强组合预测模型!
    往期精彩内容:时序预测:LSTM、ARIMA、Holt-Winters、SARIMA模型的分析与比较全是干货|数据集、学习资料、建模资源分享!EMD变体分解效果最好算法——CEEMDAN(五)-CSDN博客拒绝信息泄露!VMD滚动分解+Informer-BiLSTM并行预测模型-CSDN博客风速预测(一)数据集介绍和预处理_风......
  • 大语言模型(1)--LLaMA
    LLaMA(LargeLanguageModelMetaAI)是由MetaAI于2023年2月发布的大语言系列模型,它应该是近两年来影响力最大的自然语言处理大模型。在它的带动下,雨后春笋般地涌现出来不同语言、不同领域下的各种大模型。值得注意的是,最早Meta在非商业许可的情况下发布了LLaMA的模型权重,仅......
  • AI模型的开放与封闭:一场不断演化的博弈
    AI模型的开放与封闭:一场不断演化的博弈黑智2024年11月18日17:17北京图片来源|TIME编译|杨雪涵目前,像ChatGPT和Claude这样的顶尖AI模型通常伴随着严格的使用限制。它们的开发者对模型的访问方式进行了严格控制,以防止其被滥用。与之形成鲜明对比的是,开放模型则允许任何......
  • 大模型推理和训练所占用的显存怎么估算?
    大模型推理和训练所占用的显存怎么估算?原创 安泰Rolling AI有温度 2024年11月14日00:00 上海AI因你而升温,记得加个星标哦!在当前开源大模型中,我们可以观察到一个普遍的现象:开源可下载模型的参数规模都集中在7B、13B、65B等特定的数值上,那这种现象背后有着怎样的原因呢......
  • 【机器学习】L1与L2正则化的深度解读:如何平衡模型复杂度与性能
    L1与L2正则化的深度解读:如何平衡模型复杂度与性能1.引言:过拟合问题1.1什么是过拟合?1.2为什么会出现过拟合?主要原因:1.3正则化的基本思想2.L1正则化深度解析2.1数学表达式2.2L1正则化的特性1.稀疏解的产生2.优化特性3.权重更新规则3.L2正则化深度解析3.1数......
  • LangChain大模型AI应用开发实践:从基础到实战【文末好书推荐】
    《LangChain大模型AI应用开发实践》是一个围绕使用LangChain进行大规模AI应用开发的主题,重点介绍如何通过LangChain框架和相关技术,构建和优化AI应用。LangChain是一个面向大语言模型(LLM)开发的开源框架,特别适用于与多个外部工具、API及数据源的集成。它帮助开发者通过无缝的......
  • 大师开讲-图形学领域顶级专家王锐开讲Vulkan、VSG开源引擎
    王锐,毕业于清华大学,图形学领域顶级专家,开源技术社区的贡献者与推广者。三维引擎OpenSceneGraph的核心基石开发者与维护者,倾斜摄影数据格式osgb的发明人。著有《OpenSceneGraph3Cookbook》,《OpenSceneGraph3Beginer'sGuide》两本英文专著,并作为美国海军研究生院指定教材。......
  • 【速成】LLM大模型最新学习路线—从入门到实战!
    大语言模型学习路线:从入门到实战在人工智能领域,大语言模型(LargeLanguageModels,LLMs)正迅速成为一个热点话题。本学习路线旨在为有基本Python编程和深度学习基础的学习者提供一个清晰、系统的大模型学习指南,帮助你在这一领域快速成长。前排提示,文末有大模型AGI-CSDN独......
  • 千问 Qwen2.5-7B-Instruct 模型微调后“变身”Claude:是前世记忆还是数据版权?
    在微调阿里巴巴的开源大模型Qwen2.5-7B-Instruct时,我意外发现了一个令人震惊的现象:原本明确标识自己为“千问”的模型,在经过短时间微调后,居然声称自己是Anthropic的模型Claude。一个阿里推出的模型在微调后却自称为Anthropic的产品,确实让人感到意外和疑惑。千问与Claude......