SAF-Net:A spatio-temporal deep learning method for typhoon intensity predic 论文复现

SAF-Net:基于深度学习的台风强度预测代码实现
本文介绍了如何使用SAF-Net模型进行台风强度的时空预测,包括数据预处理、模型结构设计、训练过程以及模型在测试集上的性能评估。作者详细展示了使用PyTorch实现的代码片段,涉及数据加载、模型定义、损失函数和优化器的选择。
部署运行你感兴趣的模型镜像

视频:SAF-Net论文代码复现:台风强度变化预测《A spatio-temporal deep learning method for typhoon inten》_哔哩哔哩_bilibili

完整项目:SAF-Net论文代码复现:台风强度变化预测《SAF-Net:A spatio-temporal deep learning method for typhoon intensity predic》-优快云博客 

代码:

import pandas as pd
import numpy as np
from sklearn.preprocessing import MinMaxScaler
from sklearn.model_selection import train_test_split
 
import torch
import torch.utils.data as Data
import torch.nn as nn
import torch.nn.functional as F
import torchvision.models as models
from torch.autograd import Variable
from torchsummary import summary
import os
import random
import datetime
 
# 提前24小时预测台风
pre_seq = 4
batch_size = 128
epochs = 128
min_val_loss = 100
# 保存的模型名称
model_name = 'SAF_Net.pkl'
os.environ["CUDA_VISIBLE_DEVICES"] = "0"
 
# 读取训练集
train = pd.read_csv('data/CMA_train_'+str(pre_seq*6)+'h.csv', header=None)
print(train.shape)
 
# 读取测试集
test = pd.read_csv('data/CMA_test_'+str(pre_seq*6)+'h.csv', header=None)
print(test.shape)
 
# 合并训练集和测试集
CLIPER_feature =  pd.concat((train, test), axis=0)
CLIPER_feature.reset_index(drop=True, inplace=True)
 
# 最大最小值归一化
X_wide_scaler = MinMaxScaler()
y_scaler = MinMaxScaler()
 
X_wide = X_wide_scaler.fit_transform(CLIPER_feature.iloc[:, 5:])
X_wide_train = X_wide[0: train.shape[0], :]
 
y = y_scaler.fit_transform(CLIPER_feature.loc[:, 3].values.reshape(-1, 1))
y_train = y[0: train.shape[0], :]
 
# now 6 hours ago  12 hours ago  18 hour ago
ahead_times = [1,2,3]
 
pressures = [1000, 750, 500, 250]
 
sequential_reanalysis_u_list = []
reanalysis_u_test_dict = {}
X_deep_u_scaler_dict = {}
 
sequential_reanalysis_v_list = []
reanalysis_v_test_dict = {}
X_deep_v_scaler_dict = {}
 
# 对U进行
reanalysis_type = 'u'
for ahead_time in ahead_times:
    reanalysis_list = []
    for pressure in pressures:
        folder = None
        if ahead_time == 0:
            folder = reanalysis_type
        else:
            folder = reanalysis_type + '_' + str(ahead_time * 6)
 
        train_reanalysis_csv = pd.read_csv(
            'new/' + folder + '/' + reanalysis_type + str(pressure) + '_train_31_31.csv',
            header=None)
        test_reanalysis_csv = pd.read_csv(
            'new/' + folder + '/' + reanalysis_type + str(pressure) + '_test_31_31.csv',
            header=None)
 
        train_reanalysis = train_reanalysis_csv[train_reanalysis_csv[0].isin(train[0].unique())]
        test_reanalysis = test_reanalysis_csv[test_reanalysis_csv[0].isin(test[0].unique())]
        reanalysis_u_test_dict[reanalysis_type + str(pressure) + str(ahead_time)] = test_reanalysis  # 保存test 用于后面测试
 
        reanalysis = pd.concat((train_reanalysis, test_reanalysis), axis=0)
        reanalysis.reset_index(drop=True, inplace=True)
 
        scaler_name = reanalysis_type + str(pressure) + str(ahead_time)
        X_deep_u_scaler_dict[scaler_name] = MinMaxScaler()
 
        # 5:end is the 31*31 u component wind speed
        X_deep = X_deep_u_scaler_dict[scaler_name].fit_transform(reanalysis.loc[:, 5:])
 
        # (batch, type, channel, height, widht, time) here type is u
        X_deep_final = X_deep[0: train.shape[0], :].reshape(-1, 1, 1, 31, 31, 1)
        reanalysis_list.append(X_deep_final)
 
    X_deep_temp = np.concatenate(reanalysis_list[:], axis=2)
    print("ahead_time:", ahead_time, X_deep_temp.shape)
    sequential_reanalysis_u_list.append(X_deep_temp)
 
X_deep_u_train = np.concatenate(sequential_reanalysis_u_list, axis=5)
 
reanalysis_type = 'v'
for ahead_time in ahead_times:
    reanalysis_list = []
    for pressure in pressures:
        folder = None
        if ahead_time == 0:
            folder = reanalysis_type
        else:
            folder = reanalysis_type + '_' + str(ahead_time * 6)
 
        train_reanalysis_csv = pd.read_csv(
            'new/' + folder + '/' + reanalysis_type + str(pressure) + '_train_31_31.csv',
            header=None)
        test_reanalysis_csv = pd.read_csv(
            'new/' + folder + '/' + reanalysis_type + str(pressure) + '_test_31_31.csv',
            header=None)
 
        train_reanalysis = train_reanalysis_csv[train_reanalysis_csv[0].isin(train[0].unique())]
        test_reanalysis = test_reanalysis_csv[test_reanalysis_csv[0].isin(test[0].unique())]
        reanalysis_v_test_dict[reanalysis_type + str(pressure) + str(ahead_time)] = test_reanalysis  # 保存test 用于后面测试
 
        reanalysis = pd.concat((train_reanalysis, test_reanalysis), axis=0)
        reanalysis.reset_index(drop=True, inplace=True)
 
        scaler_name = reanalysis_type + str(pressure) + str(ahead_time)
        X_deep_v_scaler_dict[scaler_name] = MinMaxScaler()
 
        # 5:end is the 31*31 v component wind speed
        X_deep = X_deep_v_scaler_dict[scaler_name].fit_transform(reanalysis.loc[:, 5:])
 
        # (batch, type, channel, height, widht, time) here type is v
        X_deep_final = X_deep[0: train.shape[0], :].reshape(-1, 1, 1, 31, 31, 1)
        reanalysis_list.append(X_deep_final)
 
    X_deep_temp = np.concatenate(reanalysis_list[:], axis=2)
    print("ahead_time:", ahead_time, X_deep_temp.shape)
    sequential_reanalysis_v_list.append(X_deep_temp)
 
X_deep_v_train = np.concatenate(sequential_reanalysis_v_list, axis=5)
 
# 合并u和v
X_deep_train = np.concatenate((X_deep_u_train, X_deep_v_train), axis=1)
X_wide_train.shape, X_deep_train.shape
 
 
class TrainLoader(Data.Dataset):
    def __init__(self, X_wide_train, X_deep_train, y_train):
        self.X_wide_train = X_wide_train
        self.X_deep_train = X_deep_train
        self.y_train = y_train
 
    def __getitem__(self, index):
        return [self.X_wide_train[index], self.X_deep_train[index]], self.y_train[index]
 
    def __len__(self):
        return len(self.X_wide_train)
 
full_train_index = [*range(0, len(X_wide_train))]
 
train_index, val_index, _, _, = train_test_split(full_train_index,full_train_index,test_size=0.1)
 
# 训练数据集
train_dataset = torch.utils.data.DataLoader(
    TrainLoader(X_wide_train[train_index], X_deep_train[train_index], y_train[train_index]),
                                                 batch_size=batch_size, shuffle=True)
 
# 验证数据集
val_dataset = torch.utils.data.DataLoader(
    TrainLoader(X_wide_train[val_index], X_deep_train[val_index], y_train[val_index]),
                                                 batch_size=batch_size, shuffle=True)
 
 
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        # spatial attention
        self.att_block_1 = nn.Sequential(
            nn.Conv2d(in_channels=64, out_channels=64, kernel_size=1, padding=0),
            nn.BatchNorm2d(64),
            nn.ReLU(inplace=True),
            nn.Conv2d(in_channels=64, out_channels=64, kernel_size=1, padding=0),
            nn.BatchNorm2d(64),
            nn.Sigmoid(),
        )
        self.att_block_2 = nn.Sequential(
            nn.Conv2d(in_channels=128, out_channels=128, kernel_size=1, padding=0),
            nn.BatchNorm2d(128),
            nn.ReLU(inplace=True),
            nn.Conv2d(in_channels=128, out_channels=128, kernel_size=1, padding=0),
            nn.BatchNorm2d(128),
            nn.Sigmoid(),
        )
        self.att_block_3 = nn.Sequential(
            nn.Conv2d(in_channels=256, out_channels=256, kernel_size=1, padding=0),
            nn.BatchNorm2d(256),
            nn.ReLU(inplace=True),
            nn.Conv2d(in_channels=256, out_channels=256, kernel_size=1, padding=0),
            nn.BatchNorm2d(256),
            nn.Sigmoid(),
        )
        # cross
        self.cross_unit = nn.Parameter(data=torch.ones(len(ahead_times), 6))
        # fuse
        self.fuse_unit = nn.Parameter(data=torch.ones(len(ahead_times), 4))
 
        # deep
        self.conv1 = nn.Conv2d(4, 64, kernel_size=3, padding=(1, 1))
        self.pool = nn.MaxPool2d(2, 2)
        self.conv2 = nn.Conv2d(64, 128, kernel_size=3, padding=(1, 1))
        self.conv3 = nn.Conv2d(128, 256, kernel_size=3, padding=(1, 1))
        self.fc1 = nn.Linear(256 * 3 * 3, 128)
        self.fc2 = nn.Linear(96 + 128 * len(ahead_times), 64)
        self.fc3 = nn.Linear(64, 1)
 
    def forward(self, wide, deep):
        seq_list = []
        for i in range(len(ahead_times)):
            deep_u = deep[:, 0, :, :, :, i]
            deep_v = deep[:, 1, :, :, :, i]
 
            # split 1
            deep_u = self.pool(F.relu(self.conv1(deep_u)))
            deep_u = self.att_block_1(deep_u) * deep_u
 
            deep_v = self.pool(F.relu(self.conv1(deep_v)))
            deep_v = self.att_block_1(deep_v) * deep_v
 
            # fuse 1
            time_seq_1 = self.cross_unit[i][0] / (self.cross_unit[i][0] + self.cross_unit[i][1]) * deep_u + \
                         self.cross_unit[i][1] / (self.cross_unit[i][0] + self.cross_unit[i][1]) * deep_v
            time_seq_1 = self.pool(F.relu(self.conv2(time_seq_1)))
            time_seq_1 = self.att_block_2(time_seq_1) * time_seq_1
 
            # split 2
            deep_u = self.pool(F.relu(self.conv2(deep_u)))
            deep_u = self.att_block_2(deep_u) * deep_u
 
            deep_v = self.pool(F.relu(self.conv2(deep_v)))
            deep_v = self.att_block_2(deep_v) * deep_v
 
            # fuse 2
            time_seq_2 = self.cross_unit[i][2] / (self.cross_unit[i][2] + self.cross_unit[i][3]) * deep_u + \
                         self.cross_unit[i][3] / (self.cross_unit[i][2] + self.cross_unit[i][3]) * deep_v
            time_seq_2 = self.fuse_unit[i][0] / (self.fuse_unit[i][0] + self.fuse_unit[i][1]) * time_seq_1 + \
                         self.fuse_unit[i][1] / (self.fuse_unit[i][0] + self.fuse_unit[i][1]) * time_seq_2
            time_seq_2 = self.pool(F.relu(self.conv3(time_seq_2)))
            time_seq_2 = self.att_block_3(time_seq_2) * time_seq_2
 
            # split 3
            deep_u = self.pool(F.relu(self.conv3(deep_u)))
            deep_u = self.att_block_3(deep_u) * deep_u
 
            deep_v = self.pool(F.relu(self.conv3(deep_v)))
            deep_v = self.att_block_3(deep_v) * deep_v
 
            # fuse 3
            time_seq = self.cross_unit[i][4] / (self.cross_unit[i][4] + self.cross_unit[i][5]) * deep_u + \
                       self.cross_unit[i][5] / (self.cross_unit[i][4] + self.cross_unit[i][5]) * deep_v
            time_seq = self.fuse_unit[i][2] / (self.fuse_unit[i][2] + self.fuse_unit[i][3]) * time_seq_2 + \
                       self.fuse_unit[i][3] / (self.fuse_unit[i][2] + self.fuse_unit[i][3]) * time_seq
            time_seq = self.att_block_3(time_seq) * time_seq
 
            time_seq = time_seq.view(-1, 256 * 3 * 3)
            time_seq = self.fc1(time_seq)
            seq_list.append(time_seq)
        wide = wide.view(-1, 96)
        wide_n_deep = torch.cat((wide, seq_list[0]), 1)
        if len(ahead_times) > 1:
            for i in range(1, len(ahead_times)):
                wide_n_deep = torch.cat((wide_n_deep, seq_list[i]), 1)
        wide_n_deep = F.relu(self.fc2(wide_n_deep))
        wide_n_deep = F.relu(self.fc3(wide_n_deep))
        return wide_n_deep
 
 
net = Net()
 
# 利用GPU环境进行训练
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
net = net.to(device)
 
# 损失函数
criterion = nn.L1Loss()
# 优化器
optimizer = torch.optim.Adam(net.parameters(), lr=0.0007)
 
full_train_index = [*range(0, len(X_wide_train))]
 
for epoch in range(epochs):  # loop over the dataset multiple times
    train_index, val_index, _, _, = train_test_split(full_train_index, full_train_index, test_size=0.1)
    train_dataset = torch.utils.data.DataLoader(
        TrainLoader(X_wide_train[train_index], X_deep_train[train_index], y_train[train_index]),
        batch_size=batch_size, )
    val_dataset = torch.utils.data.DataLoader(
        TrainLoader(X_wide_train[val_index], X_deep_train[val_index], y_train[val_index]),
        batch_size=batch_size, )
    # training
    total_train_loss = 0
    for step, (batch_x, batch_y) in enumerate(train_dataset):
        # if torch.cuda.is_available():
        #     net.cuda()
        X_wide_train_cuda = batch_x[0].float()#.cuda()
        X_deep_train_cuda = batch_x[1].float()#.cuda()
        y_train_cuda = batch_y#.cuda()
        # zero the parameter gradients
        optimizer.zero_grad()
 
        # forward + backward + optimize
        pred_y = net(X_wide_train_cuda, X_deep_train_cuda)
        loss = criterion(pred_y, y_train_cuda)
        total_train_loss += loss.item()
        loss.backward()
        optimizer.step()
 
    # validating
    total_val_loss = 0
    for _, (batch_val_x, batch_val_y) in enumerate(val_dataset):
 
        #if torch.cuda.is_available():
        X_wide_val_cuda = batch_val_x[0].float()#.cuda()
        X_deep_val_cuda = batch_val_x[1].float()#.cuda()
        y_val_cuda = batch_val_y#.cuda()
 
        pred_y = net(X_wide_val_cuda, X_deep_val_cuda)
        val_loss = criterion(pred_y, y_val_cuda)
        total_val_loss += val_loss.item()
        # print statistics
    if min_val_loss > total_val_loss:
        torch.save(net.state_dict(), model_name)
        min_val_loss = total_val_loss
    print('epochs [%d/%d] train_loss: %.5f val_loss: %.5f' % (epoch + 1, epochs, total_train_loss, total_val_loss))
 
print('Finished Training')
 
#  调用网络
net.load_state_dict(torch.load(model_name))
# 测试年份
years = test[4].unique()
# 测试数据列表
test_list = []
for year in years:
    temp = test[test[4]==year]
    temp = temp.reset_index(drop=True)
    test_list.append(temp)
len(test_list)
 
# 计算模型分别对4个测试年份的台风强度预测的平均误差
with torch.no_grad():
    for year, _test in zip(years, test_list):
 
        print(year, '年:')
        y_test = _test.loc[:, 3]
        X_wide_test = X_wide_scaler.transform(_test.loc[:, 5:])
 
        final_test_u_list = []
        for ahead_time in ahead_times:
            year_test_list = []
            for pressure in pressures:
                scaler_name = 'u' + str(pressure) + str(ahead_time)
                X_deep = reanalysis_u_test_dict[scaler_name][
                             reanalysis_u_test_dict[scaler_name][0].isin(_test[0].unique())].loc[:, 5:]
                X_deep = X_deep_u_scaler_dict[scaler_name].transform(X_deep)
                X_deep_final = X_deep.reshape(-1, 1, 1, 31, 31, 1)
                year_test_list.append(X_deep_final)
            X_deep_temp = np.concatenate(year_test_list, axis=2)
            final_test_u_list.append(X_deep_temp)
        X_deep_u_test = np.concatenate(final_test_u_list, axis=5)
 
        final_test_v_list = []
        for ahead_time in ahead_times:
            year_test_list = []
            for pressure in pressures:
                scaler_name = 'v' + str(pressure) + str(ahead_time)
                X_deep = reanalysis_v_test_dict[scaler_name][
                             reanalysis_v_test_dict[scaler_name][0].isin(_test[0].unique())].loc[:, 5:]
                X_deep = X_deep_v_scaler_dict[scaler_name].transform(X_deep)
                X_deep_final = X_deep.reshape(-1, 1, 1, 31, 31, 1)
                year_test_list.append(X_deep_final)
            X_deep_temp = np.concatenate(year_test_list, axis=2)
            final_test_v_list.append(X_deep_temp)
        X_deep_v_test = np.concatenate(final_test_v_list, axis=5)
 
        X_deep_test = np.concatenate((X_deep_u_test, X_deep_v_test), axis=1)
 
        if torch.cuda.is_available():
            X_wide_test = Variable(torch.from_numpy(X_wide_test).float().cuda())
            X_deep_test = Variable(torch.from_numpy(X_deep_test).float().cuda())
 
        pred = net(X_wide_test, X_deep_test)
 
        pred = y_scaler.inverse_transform(pred.cpu().detach().numpy().reshape(-1, 1))
        true = y_test.values.reshape(-1, 1)
        diff = np.abs(pred - true)
 
        print('avg wind error:', sum(diff) / len(diff))

您可能感兴趣的与本文相关的镜像

PyTorch 2.9

PyTorch 2.9

PyTorch
Cuda

PyTorch 是一个开源的 Python 机器学习库,基于 Torch 库,底层由 C++ 实现,应用于人工智能领域,如计算机视觉和自然语言处理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值