当前位置: 首页 > news >正文

基于时间卷积网络TCN实现电力负荷多变量时序预测(PyTorch版)

BiTCN
前言

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

本文使用torch.nn.Conv1d卷积模块实现时间卷积网络TCN,论文链接:https://arxiv.org/pdf/1803.01271
cnn
时间卷积网络

目录

  • 1. 数据集介绍
  • 2. 数据可视化
  • 3. 特征工程
    • 3.1 特征缩放(归一化)
    • 3.2 构建监督学习数据
    • 3.3 数据集划分(Subset)
    • 3.4 数据加载器
  • 4. 构建时序预测模型(TSF)
    • 4.1 构建TCN模型
    • 4.2 实例化模型、定义损失函数与优化器
    • 4.3 模型概要
  • 5. 模型训练
    • 5.1 定义训练函数
    • 5.2 定义评估函数
    • 5.3 定义早停法并保存模型
    • 5.4 定义模型训练主程序
    • 5.5 执行模型训练过程
  • 6. 模型预测
    • 6.1 构建预测函数
  • 7. 模型验证
    • 7.1 验证集预测
    • 7.2 验证集评估
      • 7.2.1 回归拟合图
      • 7.2.2 评估指标
  • 8. 模型测试
    • 8.1 测试集预测
    • 8.2 测试集评估
      • 8.2.1 回归拟合图
      • 8.2.2 评估指标
  • 预测可视化
  • 完整源码

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 snsimport torch
import torch.nn as nn
from torch.utils.data import DataLoader, TensorDataset, Subset
from torchinfo import summary
from torchmetrics.functional.regression import (mean_absolute_error,mean_absolute_percentage_error,mean_squared_error,mean_squared_log_error,r2_score
)
np.random.seed(0)
torch.manual_seed(0)
df = pd.read_csv('../ETTh1.csv', index_col=0, parse_dates=True)
print(df.head(5))
                      HUFL   HULL   MUFL   MULL   LUFL   LULL         OT
date                                                                    
2016-07-01 00:00:00  5.827  2.009  1.599  0.462  4.203  1.340  30.531000
2016-07-01 01:00:00  5.693  2.076  1.492  0.426  4.142  1.371  27.787001
2016-07-01 02:00:00  5.157  1.741  1.279  0.355  3.777  1.218  27.787001
2016-07-01 03:00:00  5.090  1.942  1.279  0.391  3.807  1.279  25.044001
2016-07-01 04:00:00  5.358  1.942  1.492  0.462  3.868  1.279  21.948000

2. 数据可视化

这里我们使用matplotlib库实现预测数据的可视化,以便观察数据的趋势

plt.style.use('seaborn-v0_8-whitegrid')
fig, ax = plt.subplots(figsize=(20, 6))# 绘制数据
ax.plot(df['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()

趋势

3. 特征工程

3.1 特征缩放(归一化)

接下来我们按照公式 x s t d = x − x m i n x m a x − x m i n x_{std}=\frac{x-x_{min}} {x_{max}-x_{min}} xstd=xmaxxminxxmin 进行数据归一化,详细解释参考文章 机器学习:基于XGBoost极端梯度提升实现股票价格预测——TimeSeriesSplit交叉验证与GridSearchCV超参数调优详解

在单变量预测中,‌过往目标数据是唯一的输入特征‌,模型通过分析目标变量自身的历史规律进行预测。然而,在多变量预测中,‌过往目标数据与其他外部特征结合构成模型的输入特征,但目标变量的历史信息乃是核心。

X = df # 选取特征,目标数据与其他外部特征结合
X_std = (X - X.min(axis=0)) / (X.max(axis=0) - X.min(axis=0)) # 特征缩放
print(X_std)
                         HUFL      HULL      MUFL      MULL      LUFL  \
date                                                                    
2016-07-01 00:00:00  0.615599  0.454943  0.628980  0.467510  0.556576   
2016-07-01 01:00:00  0.612708  0.459449  0.626458  0.464878  0.550279   
2016-07-01 02:00:00  0.601143  0.436920  0.621438  0.459689  0.512595   
2016-07-01 03:00:00  0.599698  0.450437  0.621438  0.462320  0.515693   
2016-07-01 04:00:00  0.605480  0.450437  0.626458  0.467510  0.521990   
...                       ...       ...       ...       ...       ...   
2018-06-26 15:00:00  0.453765  0.558574  0.458955  0.589577  0.481107   
2018-06-26 16:00:00  0.371392  0.608137  0.376064  0.599956  0.487404   
2018-06-26 17:00:00  0.550572  0.576597  0.572038  0.587018  0.506298   
2018-06-26 18:00:00  0.689299  0.576597  0.720262  0.587018  0.500000   
2018-06-26 19:00:00  0.708091  0.558574  0.737019  0.548059  0.506298   LULL        OT  
date                                     
2016-07-01 00:00:00  0.613765  0.691018  
2016-07-01 01:00:00  0.620783  0.636233  
2016-07-01 02:00:00  0.586144  0.636233  
2016-07-01 03:00:00  0.599955  0.581468  
2016-07-01 04:00:00  0.599955  0.519656  
...                       ...       ...  
2018-06-26 15:00:00  0.655196  0.299159  
2018-06-26 16:00:00  0.689608  0.301955  
2018-06-26 17:00:00  0.655196  0.286521  
2018-06-26 18:00:00  0.634594  0.276679  
2018-06-26 19:00:00  0.641386  0.272466  [17420 rows x 7 columns]

3.2 构建监督学习数据

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

lag = 30  # 时间步
x_array = np.array([X_std[i:i+lag] for i in range(len(X_std) - lag)])
y_array = np.array(X_std.iloc[lag:, -1]).reshape(-1, 1)
x_tensor = torch.tensor(x_array, dtype=torch.float)
y_tensor = torch.tensor(y_array, dtype=torch.float)
print(x_tensor.shape, y_tensor.shape)  # 检查一下数据维度
torch.Size([17390, 30, 7]) torch.Size([17390, 1])

3.3 数据集划分(Subset)

使用 torch.utils.data 模块中的 Subset 划分数据集,本质是按索引进行切片,可以去查看Subset源代码

# 使用 TensorDataset 类将两个张量 x_tensor 和 y_tensor 组合成一个数据集
dataset = TensorDataset(x_tensor, y_tensor) 
train_idx = list(range(len(dataset)*3//5)) # 划分训练集索引
val_idx = list(range(len(dataset)*3//5, len(dataset)*4//5)) # 划分验证集索引
test_idx = list(range(len(dataset)*4//5, len(dataset))) # 划分测试集索引
train_set = Subset(dataset, indices=train_idx) # 创建 Subset 对象,用于训练
val_set = Subset(dataset, indices=val_idx) # 创建 Subset 对象,用于验证
test_set = Subset(dataset, indices=test_idx) # 创建 Subset 对象,用于测试

3.4 数据加载器

接下来,我们将使用 DataLoader创建数据加载器

train_loader = DataLoader(dataset=train_set, batch_size=128, shuffle=True)
valid_loader = DataLoader(dataset=val_set,batch_size=128, shuffle=False)
test_loader = DataLoader(dataset=test_set,batch_size=128, shuffle=False)

4. 构建时序预测模型(TSF)

4.1 构建TCN模型

构建Chomp1d模块,裁剪因果卷积产生的右侧多余填充‌,确保模型的时间维度对齐且严格遵循因果约束‌

class Chomp1d(nn.Module):def __init__(self, chomp_size):super(Chomp1d, self).__init__()self.chomp_size = chomp_sizedef forward(self, x):return x[:, :, :-self.chomp_size].contiguous()

在TCN残差块TemporalBlock中,Chomp1d通常与因果卷积、ReLU激活和Dropout组合使用:

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.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.relu2 = nn.ReLU()self.dropout2 = nn.Dropout(dropout)self.net = nn.Sequential(self.conv1, self.chomp1, self.relu1, self.dropout1,self.conv2, self.chomp2, self.relu2, self.dropout2)self.downsample = nn.Conv1d(n_inputs, n_outputs, 1) if n_inputs != n_outputs else Noneself.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)

TemporalConvNet 模块,通过‌堆叠多层膨胀因果卷积块‌,逐级扩大时间感受野,从而捕捉时间序列中的长期依赖关系

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 ** iin_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)

构建TCN模型的神经网络

class TCN(nn.Module):def __init__(self, input_dim, num_channels, output_dim, kernel_size=2, dropout=0.2):super(TCN, self).__init__()self.tcn = TemporalConvNet(num_inputs=input_dim,num_channels=num_channels,kernel_size=kernel_size,dropout=dropout)# 全连接层将TCN的输出映射到预测维度self.linear = nn.Linear(num_channels[-1], output_dim)def forward(self, x):# 输入形状: (batch_size, sequence_length, input_dim)x = x.permute(0, 2, 1)x = self.tcn(x)  # 输出形状: (batch_size, num_channels[-1], sequence_length)x = x[:, :, -1]  # 取最后一个时间步的输出(单步 预测)output = self.linear(x)return output

4.2 实例化模型、定义损失函数与优化器

params = {'input_dim': 7, # 'input_size',C_in'output_dim': 1, # 单步 预测'num_channels': [128] * 3,'kernel_size': 2,'dropout': .2,
}
ts_model = TCN(**params) # 实例化模型
criterion = nn.MSELoss() # 设置损失函数
optimizer = torch.optim.Adam(params=ts_model.parameters(), lr=0.0001)

在PyTorch中,可以使用torch.nn模块中的损失函数类,如nn.MSELoss用于回归问题

4.3 模型概要

summary(model=ts_model, input_size=(128, 30, 7))
==============================================================================================================
Layer (type:depth-idx)                                       Output Shape              Param #
==============================================================================================================
TCN                                                          [128, 1]                  --
├─TemporalConvNet: 1-1                                       [128, 128, 30]            --
│    └─Sequential: 2-1                                       [128, 128, 30]            --
│    │    └─TemporalBlock: 3-1                               [128, 128, 30]            36,096
│    │    └─TemporalBlock: 3-2                               [128, 128, 30]            66,048
│    │    └─TemporalBlock: 3-3                               [128, 128, 30]            66,048
├─Linear: 1-2                                                [128, 1]                  129
==============================================================================================================
Total params: 168,321
Trainable params: 168,321
Non-trainable params: 0
Total mult-adds (Units.MEGABYTES): 3.95
==============================================================================================================
Input size (MB): 0.11
Forward/backward pass size (MB): 3.93
Params size (MB): 0.00
Estimated Total Size (MB): 4.05
==============================================================================================================

5. 模型训练

5.1 定义训练函数

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

def train(model, iterator):model.train()epoch_loss = 0for batch_idx, (data, target) in enumerate(iterable=iterator):optimizer.zero_grad()output = model(data)loss = criterion(output, target)loss.backward()optimizer.step()epoch_loss += loss.item()avg_loss = epoch_loss / len(iterator)return avg_loss

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

5.2 定义评估函数

def evaluate(model, iterator): # Being used to validate and testmodel.eval()epoch_loss = 0with torch.no_grad():for batch_idx, (data, target) in enumerate(iterable=iterator):output = model(data)loss = criterion(output, target)epoch_loss += loss.item()avg_loss = epoch_loss / len(iterator)return avg_loss

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

5.3 定义早停法并保存模型

定义早停法以便在模型训练过程中调用

class EarlyStopping:def __init__(self, patience=5, delta=0.0):self.patience = patience  # 允许的连续未改进次数self.delta = delta        # 损失波动容忍阈值self.counter = 0          # 未改进计数器self.best_loss = float('inf')  # 最佳验证损失值self.early_stop = False   # 终止训练标志def __call__(self, val_loss, model):if val_loss < (self.best_loss - self.delta):self.best_loss = val_lossself.counter = 0# 保存最佳模型参数‌:ml-citation{ref="1,5" data="citationList"}torch.save(model.state_dict(), 'best_model.pth')else:self.counter +=1if self.counter >= self.patience:self.early_stop = True
EarlyStopper = EarlyStopping(patience=50, delta=0.00001)  # 设置参数

若不想使用早停法EarlyStopper,参数patience设置一个超大的值,delta设置为0,即可。

5.4 定义模型训练主程序

通过定义模型训练主程序来执行模型训练

def main():train_losses = []val_losses = []for epoch in range(1000):train_loss = train(model=ts_model, iterator=train_loader)val_loss = evaluate(model=ts_model, iterator=valid_loader)train_losses.append(train_loss)val_losses.append(val_loss)print(f'Epoch: {epoch + 1:02}, Train MSELoss: {train_loss:.5f}, Val. MSELoss: {val_loss:.5f}')# 触发早停判断EarlyStopper(val_loss, model=ts_model)if EarlyStopper.early_stop:print(f"Early stopping at epoch {epoch}")breakplt.figure(figsize=(10, 5))plt.plot(train_losses, label='Training Loss')plt.plot(val_losses, label='Validation Loss')plt.xlabel('Epoch')plt.ylabel('MSELoss')plt.title('Training and Validation Loss over Epochs')plt.legend()plt.grid(True)plt.show()

5.5 执行模型训练过程

main()
Epoch: 222, Train MSELoss: 0.00040, Val. MSELoss: 0.00032
Epoch: 223, Train MSELoss: 0.00040, Val. MSELoss: 0.00023
Epoch: 224, Train MSELoss: 0.00040, Val. MSELoss: 0.00032
Epoch: 225, Train MSELoss: 0.00041, Val. MSELoss: 0.00022
Epoch: 226, Train MSELoss: 0.00040, Val. MSELoss: 0.00025
Epoch: 227, Train MSELoss: 0.00040, Val. MSELoss: 0.00027
Epoch: 228, Train MSELoss: 0.00040, Val. MSELoss: 0.00021
Epoch: 229, Train MSELoss: 0.00040, Val. MSELoss: 0.00031
Epoch: 230, Train MSELoss: 0.00040, Val. MSELoss: 0.00024
Epoch: 231, Train MSELoss: 0.00041, Val. MSELoss: 0.00028
Epoch: 232, Train MSELoss: 0.00040, Val. MSELoss: 0.00023
Epoch: 233, Train MSELoss: 0.00040, Val. MSELoss: 0.00029
Epoch: 234, Train MSELoss: 0.00040, Val. MSELoss: 0.00023
Epoch: 235, Train MSELoss: 0.00040, Val. MSELoss: 0.00027
Epoch: 236, Train MSELoss: 0.00040, Val. MSELoss: 0.00028
Epoch: 237, Train MSELoss: 0.00040, Val. MSELoss: 0.00030
Early stopping at epoch 236

损失

6. 模型预测

6.1 构建预测函数

接下来,我们通过构建 predict 函数来对模型中的数据进行预测。

def predict(model, iterator):model.eval()targets = []predictions = []with torch.no_grad():for batch_idx, (data, target) in enumerate(iterable=iterator):output = model(data)targets.append(target)predictions.append(output)targets = torch.cat(targets)predictions = torch.cat(predictions, dim=0)return predictions, targets

这个函数的主要作用是使用给定的模型对输入的数据迭代器 iterator 中的数据进行预测,并收集相应的预测结果和真实目标值,最后返回整理好的预测值和目标值。它常用于在训练好模型之后,对测试集或者验证集等数据进行预测的场景。具体来说:

model.eval() 这行代码将模型设置为评估模式。在很多深度学习模型中,尤其是包含像 dropout、batch normalization 等在训练阶段和评估阶段行为不同的层时,调用 eval() 方法可以确保模型在预测时使用正确的计算方式。例如,在训练阶段,dropout 会按照一定概率随机丢弃神经元,而在评估阶段则不会进行这种随机丢弃操作,以保证预测结果的稳定性和确定性。

with torch.no_grad(): 不需要计算梯度。因为在预测阶段,我们并不需要进行反向传播来更新模型的参数,关闭梯度计算可以节省内存并提高计算效率。

targets = torch.cat(targets)predictions = torch.cat(predictions, dim=0):在遍历完所有批次后,使用 torch.cat 函数将收集到的 targets 列表中的张量按照维度进行拼接,使其成为一个连续的张量,方便后续对整体的预测结果和目标值进行统一的分析和处理。对于 predictions 也是同样的操作,指定了拼接维度为 0,通常在按照批次维度拼接预测结果张量时会这样做,确保拼接后的张量结构符合预期,能正确反映所有批次的预测情况。

7. 模型验证

使用 torch.load() 加载 .pth 文件,并通过 load_state_dict() 将权重映射到模型‌

ts_model.load_state_dict(state_dict=torch.load('best_model.pth'))  # 加载权重

7.1 验证集预测

val_pred, val_true = predict(ts_model, valid_loader)

7.2 验证集评估

7.2.1 回归拟合图

通过seaborn库中regplot函数绘制回归拟合图,我们可以清晰地看到模型预测值与实际数据点之间的吻合程度,即拟合度。

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

回归拟合图

7.2.2 评估指标

torchmetrics库提供了各种损失函数,我们可以直接用来计算张量的损失,而无需转换成numpy数组形式。

mae = mean_absolute_error(preds=val_pred, target=val_true)
print(f"Mean Absolute Error: {mae:.5f}")mape = mean_absolute_percentage_error(preds=val_pred, target=val_true)
print(f"Mean Absolute Percentage Error: {mape * 100:.4f}%")mse = mean_squared_error(preds=val_pred, target=val_true)
print(f"Mean Squared Error: {mse:.4f}")msle = mean_squared_log_error(preds=val_pred, target=val_true)
print(f"Mean Squared Log Error: {msle:.4f}")r2 = r2_score(preds=val_pred, target=val_true)
print(f"R²: {r2:.4f}")
Mean Absolute Error: 0.01120
Mean Absolute Percentage Error: 7.2963%
Mean Squared Error: 0.0002
Mean Squared Log Error: 0.0001: 0.9711

8. 模型测试

8.1 测试集预测

test_pred, test_true = predict(ts_model, test_loader)

8.2 测试集评估

8.2.1 回归拟合图

通过seaborn库中regplot函数绘制回归拟合图,我们可以清晰地看到模型预测值与实际数据点之间的吻合程度,即拟合度。

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

回归拟合图

8.2.2 评估指标

torchmetrics库提供了各种损失函数,我们可以直接用来计算张量的损失,而无需转换成numpy数组形式。

mae = mean_absolute_error(preds=test_pred, target=test_true)
print(f"Mean Absolute Error: {mae:.5f}")mape = mean_absolute_percentage_error(preds=test_pred, target=test_true)
print(f"Mean Absolute Percentage Error: {mape * 100:.4f}%")mse = mean_squared_error(preds=test_pred, target=test_true)
print(f"Mean Squared Error: {mse:.4f}")msle = mean_squared_log_error(preds=test_pred, target=test_true)
print(f"Mean Squared Log Error: {msle:.4f}")r2 = r2_score(preds=test_pred, target=test_true)
print(f"R²: {r2:.4f}")
Mean Absolute Error: 0.00941
Mean Absolute Percentage Error: 4.7853%
Mean Squared Error: 0.0002
Mean Squared Log Error: 0.0001: 0.9623

预测可视化

matplotlib 库中,我们可以直接使用张量数据来绘制图表

plt.figure(figsize=(20, 5))
plt.plot(torch.cat(tensors=(val_true, test_true), dim=0), label='Actual Value')
plt.plot(torch.cat(tensors=(val_pred, test_pred), dim=0), label='Prediction Value')
plt.axvline(len(val_pred), color='red', linestyle='-.')
plt.text(0, 0.4, 'Validation', fontsize=18)
plt.text(len(val_pred), 0.4, 'Test', fontsize=18)
plt.ylabel('Temperature', fontsize=18)
plt.title('Prediction Results', fontsize=24)
plt.legend()
plt.grid(True)
plt.show()

时序预测

n_idx = len(y_tensor)
val_size = len(val_idx)
test_size = len(test_idx)x_plot = list(range(len(dataset)))
y_plot = y_tensorx_val_line = x_plot[n_idx - val_size - test_size]
x_test_line = x_plot[n_idx - test_size]
plt.style.use('_mpl-gallery')
plt.figure(figsize=(16, 8))
plt.rcParams['font.family'] = 'serif'
plt.title(f'{ts_model.__class__.__name__} Prediction Results', fontsize=40, pad=20)
plt.plot(x_plot, y_plot, label='Actual Value')
plt.plot(val_idx, val_pred, label='Validation Prediction', color='green')
plt.plot(test_idx, test_pred, label='Testing Prediction', color='orange')
plt.axvline(x_val_line, color='red', linestyle='-.')
plt.axvline(x_test_line, color='red', linestyle='-.')
plt.text(x_val_line, 0.8, 'Validation', fontsize=20)
plt.text(x_test_line, 0.8, 'Test', fontsize=20)
plt.ylabel('Temperature', fontsize=30)
plt.legend()
plt.show()

预测可视化

完整源码

相关文章:

基于时间卷积网络TCN实现电力负荷多变量时序预测(PyTorch版)

前言 系列专栏:【深度学习&#xff1a;算法项目实战】✨︎ 涉及医疗健康、财经金融、商业零售、食品饮料、运动健身、交通运输、环境科学、社交媒体以及文本和图像处理等诸多领域&#xff0c;讨论了各种复杂的深度神经网络思想&#xff0c;如卷积神经网络、循环神经网络、生成对…...

ESXi8的部署过程

目录 一、系统安装 二、ESXI8的序列号 三、挂载硬盘和新建VMFS数据分区 四、通过数据存储浏览器上传下载文件 五、Windows远程桌面端口隐射 六、导出虚机 一、系统安装 1、使用UtrIOS系统制作ESXI8的启动盘; 2、服务器启动F8按键进入Popup启动选项,选择U盘启动; 3、安…...

IntelliJ IDEA 2020~2024 创建SpringBoot项目编辑报错: 程序包org.springframework.boot不存在

目录 前奏解决结尾 前奏 哈&#xff01;今天在处理我的SpringBoot项目时&#xff0c;突然遇到了一些让人摸不着头脑的错误提示&#xff1a; java: 程序包org.junit不存在 java: 程序包org.junit.runner不存在 java: 程序包org.springframework.boot.test.context不存在 java:…...

Windows 权限配置文件解析与安全分析(GPP,GPO,LSA)

在 Windows 网络环境中&#xff0c;权限配置文件用于管理用户权限、密码策略和访问控制&#xff0c;涵盖组策略首选项&#xff08;GPP&#xff09;、本地安全策略&#xff08;LSA&#xff09;、注册表以及 Active Directory 组策略&#xff08;GPO&#xff09; 等。这些配置文件…...

【微服务】基础概念

1.什么是微服务 微服务其实就是一种架构风格&#xff0c;他提倡我们在开发的时候&#xff0c;一个应用应该是一组小型服务而组成的&#xff0c;每一个服务都运行在自己的进程中&#xff0c;每一个小服务都通过HTTP的方式进行互通。他更加强调服务的彻底拆分。他并不是仅局限于…...

MYOJ_4342:(洛谷P1087)[NOIP 2004 普及组] FBI 树(二叉树实操,递归提高)

题目描述 我们可以把由 “0” 和 “1” 组成的字符串分为三类&#xff1a;全 “0” 串称为 B 串&#xff0c;全 “1” 串称为 I 串&#xff0c;既含 “0” 又含 “1” 的串则称为 F 串。 FBI 树是一种二叉树&#xff0c;它的结点类型也包括 F 结点&#xff0c;B 结点和 I 结点三…...

LLM(13):词编码后的位置

原则上&#xff0c;token 嵌入是大型语言模型&#xff08;LLM&#xff09;的合适输入。然而&#xff0c;LLM 的一个小缺点是它们的自注意力机制无法指导序列中 token 的位置或顺序。在前面介绍的嵌入层的工作方式中&#xff0c;无论 token ID 在输入序列中的位置如何&#xff0…...

MINIQMT学习课程Day4

聚宽的模拟/实盘跟单系统&#xff0c;已经全部介绍完毕&#xff0c;上传完毕了&#xff0c;相信大家已经可以进行聚宽的miniqmt的交易了。如果还有疑问&#xff0c;私信我进行沟通。 现在开始进入新的课题&#xff0c;如何学习python&#xff0c;我不教那些乱七八糟的&#xff…...

AWS云服务:大数据公司实现技术突破与商业价值的核心引擎

在数据驱动决策的时代&#xff0c;大数据公司面临着海量数据存储、实时计算、复杂分析及安全合规等核心挑战。如何高效构建弹性、可扩展且低成本的技术架构&#xff0c;成为企业能否在竞争中胜出的关键。亚马逊云科技&#xff08;AWS&#xff09;作为全球云计算领域的领导者&am…...

Openpyxl使用教程(包含处理大数据量案例)

文章目录 一、简介功能特性应用场景使用优势 二、常用方法1、工作簿wb2、工作表ws 三、案例1、创建新工作簿2、将Excel数据存入list中3、按行读取文件(适合大文件)4、按指定行读取文件(适合大文件) 一、简介 在 Python 数据处理领域&#xff0c;openpyxl 凭借其卓越的功能与易…...

蓝桥杯15届 宝石组合

问题描述 在一个神秘的森林里&#xff0c;住着一个小精灵名叫小蓝。有一天&#xff0c;他偶然发现了一个隐藏在树洞里的宝藏&#xff0c;里面装满了闪烁着美丽光芒的宝石。这些宝石都有着不同的颜色和形状&#xff0c;但最引人注目的是它们各自独特的 “闪亮度” 属性。每颗宝…...

THE UNIVERSITY OF MANCHESTER-NUMERICAL ANALYSIS 1-3.4数值积分-复合积分公式

3.4.1 复合梯形法则 梯形法则仅使用两个点来近似积分,显然对于大多数应用来说,这不足够。为了提高精度,有多种方法可以利用更多的点和函数值。正如我们刚才在Newton-Cotes方法和辛普森法则中所看到的,一种方法是使用更高阶的插值函数。另一种方法是将区间划分为更小的区间…...

嵌入式系统应用-拓展-相关开发软件说明

这里以STM32的系列产品为例子&#xff0c;利用MDK的集成开发平台进行开发过程中&#xff0c;所有相关软件安装说明。 1 集成开发环境安装 1.1 MDK 下载 1.1.1 官网下载 官方下载地址&#xff1a; https://www.keil.com/download/product/ 选择MDK-ARM &#xff0c;填写一些…...

react实现上传图片到阿里云OSS以及问题解决(保姆级)

一、优势 提高上传速度&#xff1a;前端直传利用了浏览器与 OSS 之间的直接连接&#xff0c;能够充分利用用户的网络带宽。相比之下&#xff0c;后端传递文件时&#xff0c;文件需要经过后端服务器的中转&#xff0c;可能会受到后端服务器网络环境和处理能力的限制&#xff0c;…...

嵌入式学习笔记——ARM-中断与异常

文章目录 中断与异常的区别中断与 DMA 的区别中断能否睡眠&#xff1f;下半部能否睡眠&#xff1f;1. 中断处理程序不能睡眠2. 下半部&#xff08;SoftIRQ、Tasklet、Workqueue&#xff09; 中断处理注意点1. 快进快出2. 避免阻塞3. 正确返回值4. 如何处理大量任务5. 避免竞态问…...

OpenHarmony子系统开发 - 安全(十二)

OpenHarmony SELinux开发指导&#xff08;五&#xff09; 一、OpenHarmony SELinux常见问题 neverallow编译报错处理 现象描述 编译SELinux时会进行neverallow检查&#xff0c;当配置的策略不合理时&#xff0c;可能出现违反neverallow编译报错。 neverallow check failed…...

深入解析ARM与RISC-V架构的Bring-up核心流程

深入解析ARM与RISC-V架构的Bring-up核心流程 作者&#xff1a;嵌入式架构探索者 | 2023年10月 引言 在嵌入式开发中&#xff0c;处理器的Bring-up&#xff08;启动初始化&#xff09;是系统运行的第一道门槛。ARM和RISC-V作为两大主流架构&#xff0c;其Bring-up流程既有共性…...

【力扣hot100题】(054)全排列

挺经典的回溯题的。 class Solution { public:vector<vector<int>> result;void recursion(vector<int>& nums,vector<int>& now){if(nums.size()0){result.push_back(now);return ;}for(int i0;i<nums.size();i){now.push_back(nums[i]);…...

vue中如何动态的绑定图片

在项目中遇到需要动态的改变图片路径&#xff0c;图片路径并非是从后台获取过来的数据。 因此在data中必须用require加载&#xff0c;否则会当成字符串来处理。...

湖北师范大学计信学院研究生课程《工程伦理》12.6章节练习

1【单选题】下列哪个不是数字身份的特点? A. 多样性 B. 唯一性 C. 可变性 D. 允许匿名和假名 2【单选题】下列哪项不是现代国家的基本职能。 A. 保护政权统一 B. 保护本国面对其他国家侵犯 C. 保护国内每个人免受他人侵犯 D. 承担发展国民经济 3【单选题】哪个国家在全球率先发…...

prism WPF 登录对话框登录成功后显示主界面

prism WPF 登录对话框登录成功后显示主界面 项目结构 LoginUC.xaml <UserControl x:Class"PrismWpfApp.Views.LoginUC"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml…...

MySQL统计信息

1. 什么是统计信息&#xff1f; 统计信息就像是数据库的"地图"&#xff0c;它告诉优化器&#xff1a; 每个表有多大&#xff08;有多少行数据&#xff09; 每个索引的"区分度"&#xff08;有多少不同的值&#xff09; 数据分布情况&#xff08;哪些值出…...

Spark,配置hadoop集群2

编写Hadoop集群启停脚本 1.建立新文件&#xff0c;编写脚本程序 在hadoop101中操作&#xff0c;在/root/bin下新建文件&#xff1a;myhadoop&#xff0c;输入如下内容&#xff1a; 2.分发执行权限 保存后退出&#xff0c;然后赋予脚本执行权限 [roothadoop101 ~]$ chmod x /r…...

⭐算法OJ⭐重建行程【哈密尔顿路径】(C++ 实现)Reconstruct Itinerary

You are given a list of airline tickets where tickets[i] [from_i, to_i] represent the departure and the arrival airports of one flight. Reconstruct the itinerary in order and return it. All of the tickets belong to a man who departs from “JFK”, thus, t…...

大模型如何优化数字人的实时交互与情感表达

标题:大模型如何优化数字人的实时交互与情感表达 内容:1.摘要 随着人工智能技术的飞速发展&#xff0c;数字人在多个领域的应用愈发广泛&#xff0c;其实时交互与情感表达能力成为提升用户体验的关键因素。本文旨在探讨大模型如何优化数字人的实时交互与情感表达。通过分析大模…...

【含文档+PPT+源码】基于SpringBoot+Vue旅游管理网站

项目介绍 本课程演示的是一款 基于SpringBootVue旅游管理网站&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的 Java 学习者。 1.包含&#xff1a;项目源码、项目文档、数据库脚本、软件工具等所有资料 2.带你从零开始部署运行本套系统 3.该项目附…...

理解OSPF Stub区域和各类LSA特点

之前学习到OSPF特殊区域和各类类型LSA的分析后&#xff0c;一直很混乱&#xff0c;在网上也难找到详细的解释&#xff0c;在看了 HCNP书本内容后&#xff0c;对这块类容理解更加清晰&#xff0c;本次内容&#xff0c;我们使用实验示例&#xff0c;来对OSPF特殊区域和各 类型LSA…...

AI智算-K8s如何利用GPFS分布式并行文件存储加速训练or推理

文章目录 GPFS简介核心特性存储环境介绍存储软件版本客户端存储RoCEGPFS 管理(GUI)1. 创建 CSI 用户2. 检查GUI与k8s通信文件系统配置1. 开启配额2. 启用filesetdf文件系统3. 验证文件系统配置4. 启用自动inode扩展存储集群配置1. 启用对根文件集(root fileset)配额2. igno…...

Linux如何设置bash为默认shell

大部分情况下&#xff0c;Linux的默认shell是bash&#xff0c;但某些Linux发行版&#xff0c;例如Kali&#xff0c;默认的终端是zsh&#xff0c;本文以Kali为例&#xff0c;将Kali的默认shell从zsh改为bash。 其实Kali早期的shell也是bash&#xff0c;2020 版本之后&#xff1a…...

leetcode-代码随想录-链表-翻转链表

题目 链接&#xff1a;206. 反转链表 - 力扣&#xff08;LeetCode&#xff09; 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1]class Solution { public:ListNode* rev…...

CSS快速上手

第一章 CSS基础 首先来回答2个问题。 1.CSS是什么&#xff1f; CSS是用来控制网页外观的一门技术。 2.前端最核心的技术是什么&#xff1f;他们分别是用来干吗的&#xff1f; 前端最核心的技术有&#xff1a;HTML、CSS、JavaScript。 HTML用于控制网页的结构&#xff0c;CSS…...

虚拟现实 UI 设计:打造沉浸式用户体验

VR UI 设计基础与特点 虚拟现实技术近年来发展迅猛&#xff0c;其独特的沉浸式体验吸引了众多领域的关注与应用。在 VR 环境中&#xff0c;UI 设计扮演着至关重要的角色&#xff0c;它是用户与虚拟世界交互的桥梁。与传统 UI 设计相比&#xff0c;VR UI 设计具有显著的特点。传…...

搜索与图论 树的广度优先遍历 图中点的层次

适用性 当边的权值相等时&#xff0c;使用广度优先遍历&#xff0c;往往是求图&#xff08;树&#xff09;的最短路径最优方法 抽象理解 伪代码 建立队列 添加第一个起始点到队列&#xff0c;标记其不可访问 while(队列不为空)//开始循环{获取队列中的队首元素&#xff0c;获…...

DHCP之报文格式

字段说明&#xff1a; op (op code): 表示报文的类型&#xff0c;取值为 1 或 2&#xff0c;含义如下 1:客户端请求报 2:服务器响应报文 Secs (seconds):由客户端填充&#xff0c;表示从客户端开始获得 IP 地址或 IP 地址续借后所使用了的秒数&#xff0c;缺省值为 3600s。 F…...

Docker安装、配置Redis

1.如果没有docker-compose.yml文件的话&#xff0c;先创建docker-compose.yml 配置文件一般长这个样子 version: 3services:redis:image: redis:latestcontainer_name: redisports:- "6379:6379"command: redis-server --requirepass "123456"restart: a…...

空中无人机等动态目标识别2025.4.4

* 一.无人机动态数据概述* 1.1 空中动态数据定义 在无人机动态数据的范畴中&#xff0c; 空中动态数据 是一个核心概念。它主要包括无人机在飞行过程中产生的各种实时信息&#xff0c;如 位置、速度、高度、姿态 等[1]。这些数据通过传感器系统采集&#xff0c;并以特定格式存…...

【AI论文】通过R1-Zero类似训练改进视觉空间推理

摘要&#xff1a;人们越来越关注提升多模态大型语言模型&#xff08;MLLMs&#xff09;的推理能力。作为在物理领域中运作的人工智能代理的基石&#xff0c;基于视频的视觉空间智能&#xff08;VSI&#xff09;成为MLLMs最为关键的推理能力之一。本研究首次深入探讨了通过R1-Ze…...

游戏引擎学习第203天

回顾当前情况 在这里我将直播完成整个游戏的制作。我们现在面临一些技术上的困难&#xff0c;确实如此。我的笔记本电脑的电源接口坏了&#xff0c;所以我不得不准备了这台备用笔记本&#xff0c;希望它能够正常工作。我所以希望一切都还好&#xff0c;尽管我不完全确定是否一…...

从菜鸟到高手的提示词优化指南‌

如何用“说话的艺术”榨干AI潜力&#xff1f; ——从菜鸟到高手的提示词优化指南‌ 一、什么是好的提示词&#xff1f; 核心公式‌&#xff1a;精准提问 明确需求 限定条件 示范案例 好比让AI帮你买咖啡—— ❌ 差提示&#xff1a;“帮我买杯咖啡”&#xff08;AI可能随便…...

应对高并发的根本挑战:思维转变【大模型总结】

以下是对这篇技术总结的详细解析&#xff0c;以分步说明的形式呈现&#xff0c;帮助理解亿万并发场景下的核心策略与创新思维&#xff1a; 一、应对高并发的根本挑战&#xff1a;思维转变 1. 传统架构的局限 问题&#xff1a;传统系统追求零故障和强一致性&#xff0c;但在海…...

【Java集合】单列集合List详解

参考笔记&#xff1a; java 单列集合List 万字详解&#xff08;通俗易懂&#xff09;_java singlelist-CSDN博客 目录 前言&#xff1a; 一、概述 二、特点 三、使用集合的经典四部曲 四、List接口常用的方法 五、List接口实现类——ArrayList 六、List接口实现类——Ve…...

蓝桥刷题note13(排序)

1.冒泡排序 适用场景&#xff1a; 数据量较小&#xff1a;适用于数据量较小的情况&#xff0c;例如数组长度在 10 以内。 优点 稳定性&#xff1a;冒泡排序是一种稳定的排序算法&#xff0c;相同元素的相对顺序不会改变。 缺点 时间复杂度高&#xff1a;平均和最坏时间复杂度为…...

【AI模型核心流程】(一)大语言模型输入处理机制详解与常见误解辨析

一、引言 大语言模型&#xff08;LLM&#xff09;如GPT、BERT、LLaMA等&#xff0c;已成为自然语言处理领域的核心技术。然而&#xff0c;许多开发者对其底层输入处理机制存在误解&#xff0c;尤其是从自然语言文本到模型可理解的向量表示这一过程。本文将从技术细节出发&…...

如何完整迁移 Git 仓库 ?

Git 已经成为软件开发中版本控制和协作的事实上的标准。有时&#xff0c;开发人员可能需要将整个 Git 存储库 (包括其历史记录、分支和标记) 移动到新的位置或托管服务。在这个全面的指南中&#xff0c;我们将讨论在不丢失任何关键数据或历史记录的情况下无缝地重新定位完整 Gi…...

《在 Ubuntu 22.04 上安装 CUDA 11.8 和 Anaconda,并配置环境变量》

安装 CUDA 11.8 和 Anaconda 并配置环境变量 在本教程中&#xff0c;我们将介绍如何在 Ubuntu 22.04 上安装 CUDA 11.8 和 Anaconda&#xff0c;并配置相应的环境变量。我们还将配置使用 阿里云镜像源 来加速软件包更新。以下是具体步骤。 步骤 1&#xff1a;更新软件源 首先…...

残差神经网络(ResNet)概念解析与用法实例:简洁的图像处理任务

目录 1. 前言 2. ResNet的核心思想 2.1 残差学习 2.2 跳跃连接 3. ResNet的架构 3.1 残差块 3.2 ResNet的整体架构 4. ResNet实例&#xff1a;随便处理处理图像 5. 总结 1. 前言 随着深度学习的发展&#xff0c;神经网络的层数不断增加&#xff0c;但随之而来的是梯度…...

家里网络访问Github有时候打不开,解决办法

1、修改Hosts文件修改法 通过DNS查询工具&#xff08;如&#xff09;获取最新GitHub域名解析IP修改系统hosts文件&#xff08;路径&#xff1a;C:\Windows\System32\drivers\etc\hosts&#xff09;&#xff0c;添加&#xff1a;20.205.243.166 github.com 20.27.177.113 github…...

VirtualBox 配置双网卡(NAT + 桥接)详细步骤

在 VirtualBox 中为 CentOS 虚拟机配置双网卡&#xff08;NAT 桥接&#xff09;&#xff0c;使其既能访问外网&#xff08;NAT&#xff09;&#xff0c;又能与宿主机&#xff08;Windows 10&#xff09;或局域网通信&#xff08;桥接&#xff09;。 步骤 1&#xff1a;关闭虚…...

【2023】ORIGIN或MATLAB 颜色图,等高图,颜色条——需要拟合补全中间的颜色

前言 不是我疯了,就是世界疯了。我不知道究竟是哪一个疯了。瓶口和瓶盖尺寸不符。也许该怪瓶子,也许该怪盖子。但不管怎样,尺寸不符的事实不容动摇——《1Q84》 \;\;\;\;\;\; 有十几二十个导出的曲线数据,其中第一列是频率点,大约1001个,第二列是某种数据,都在0~1之间…...

flutter 专题 七十三Flutter打包未签名的ipa

在Flutter项目开发完成之后&#xff0c;需要把iOS项目拿给第三方&#xff08;如打包机&#xff09;进行签名&#xff0c;那我们首先就需要准备打包好未签名的的ipa包。 打包之前&#xff0c;需要先从第三方获取到iOS证书(.p12)和描述文件(.mobileprovision)&#xff0c;然后然…...