| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129 |
- import math
- import torch
- import torch.nn as nn
- class PositionalEncoding(nn.Module):
- """
- 正弦位置编码
- 输入: [batch, seq_len, d_model]
- 输出: [batch, seq_len, d_model]
- """
- def __init__(self, d_model, max_len=5000, dropout=0.1):
- super().__init__()
- self.dropout = nn.Dropout(dropout)
- pe = torch.zeros(max_len, d_model)
- position = torch.arange(0, max_len, dtype=torch.float32).unsqueeze(1)
- div_term = torch.exp(
- torch.arange(0, d_model, 2, dtype=torch.float32)
- * (-math.log(10000.0) / d_model)
- )
- pe[:, 0::2] = torch.sin(position * div_term)
- # 如果 d_model 是奇数,这里要避免维度不匹配
- if d_model % 2 == 0:
- pe[:, 1::2] = torch.cos(position * div_term)
- else:
- pe[:, 1::2] = torch.cos(position * div_term[:-1])
- pe = pe.unsqueeze(0) # [1, max_len, d_model]
- self.register_buffer("pe", pe)
- def forward(self, x):
- seq_len = x.size(1)
- x = x + self.pe[:, :seq_len, :]
- return self.dropout(x)
- class TransformerEncoderForecaster(nn.Module):
- """
- Transformer Encoder 时间序列预测模型
- 输入:
- x: [batch, input_len, n_features]
- 输出:
- y_pred: [batch, pred_len]
- """
- def __init__(
- self,
- n_features,
- pred_len,
- d_model=128,
- n_heads=8,
- num_layers=3,
- dim_feedforward=256,
- dropout=0.1,
- pooling="last", # 可选: "last" 或 "mean"
- ):
- super().__init__()
- self.pred_len = pred_len
- self.pooling = pooling
- # 将原始多变量特征映射到 Transformer 的隐藏维度
- self.input_projection = nn.Linear(n_features, d_model)
- # 位置编码
- self.pos_encoder = PositionalEncoding(
- d_model=d_model,
- max_len=5000,
- dropout=dropout,
- )
- # Transformer Encoder 层
- encoder_layer = nn.TransformerEncoderLayer(
- d_model=d_model,
- nhead=n_heads,
- dim_feedforward=dim_feedforward,
- dropout=dropout,
- activation="gelu",
- batch_first=True,
- norm_first=True,
- )
- self.encoder = nn.TransformerEncoder(
- encoder_layer=encoder_layer,
- num_layers=num_layers,
- )
- # 输出层:将编码后的历史信息映射到未来 pred_len 个预测值
- self.head = nn.Sequential(
- nn.LayerNorm(d_model),
- nn.Linear(d_model, 128),
- nn.GELU(),
- nn.Dropout(dropout),
- nn.Linear(128, pred_len),
- )
- def forward(self, x):
- # x: [batch, input_len, n_features]
- x = self.input_projection(x) # [batch, input_len, d_model]
- x = self.pos_encoder(x) # [batch, input_len, d_model]
- x = self.encoder(x) # [batch, input_len, d_model]
- if self.pooling == "mean":
- x = x.mean(dim=1) # [batch, d_model]
- else:
- x = x[:, -1, :] # [batch, d_model]
- y_pred = self.head(x) # [batch, pred_len]
- return y_pred
- if __name__ == "__main__":
- model = TransformerEncoderForecaster(n_features=10, pred_len=288, d_model=128, n_heads=8, num_layers=3, dim_feedforward=256, dropout=0.1, pooling="last")
- print(model)
- # 构造随机输入数据: [batch, input_len, n_features]
- import torch
- batch_size = 4
- input_len = 288
- n_features = 10
- x = torch.randn(batch_size, input_len, n_features)
- # 前向传播
- y_pred = model(x)
- print("输出 shape:", y_pred.shape)
|