【Datawhale AI 夏令营第三期--深度学习-从零入门 AI for Science-Task1:赛事初探——降水预测模型搭建过程概述学习笔记】

AI极端降水预报

赛题背景

在全球变暖背景下,极端降水发生频次更多、范围更广、强度更强,其时空尺度上也呈现出非典型的特征。2023年夏季,我国共发生 17次暴雨过程,引发严重洪涝灾害,对人民生活和社会经济造成极大影响。2022年以来基于数据驱动的大模型开始逐步超过基于物理的气象模型预报能力。本次大赛考察选手基于业界领先的伏羲气象大模型输出,进一步优化和提升未来三天的极端降水预测。

任务和主题

AI极端降水预报:提供历史时段伏羲气象大模型未来72小时逐小时的多个气象要素以及对应时段的ERA5降水数据,输出给定时段的基于伏羲气象大模型要素作为输入的AI极端降水预测。

比赛数据

在这里插入图片描述

Baseline代码

1.安装包

!pip install xarray[complete]
!apt update&&apt install axel
# 安装 Python 库 xarray,它是一种用于处理多维数组的库。[complete] 表示安装所有可选的依赖项,使功能更为完善。
# 首先更新系统的包列表,然后安装 axel,一个多线程下载工具。&& 表示前一个命令成功执行后再执行后面的命令。
# 训练和测试数据集的下载
!axel -n 5 -o weather.round1.train.gt.2019-2021.zip 'https://tianchi-race-prod-sh.oss-cn-shanghai.aliyuncs.com/file/race/documents/532234/bigFile/weather.round1.train.gt.2019-2021.zip?Expires=1722096703&OSSAccessKeyId=LTAI5t7fj2oKqzKgLGz6kGQc&Signature=ySj%2BSeByz1luvLTaOg2b97W6Gmw%3D&response-content-disposition=attachment%3B%20'
!axel -n 5 -o weather.round1.test.zip 'https://tianchi-race-prod-sh.oss-cn-shanghai.aliyuncs.com/file/race/documents/532234/bigFile/weather.round1.test.zip?Expires=1722096756&OSSAccessKeyId=LTAI5t7fj2oKqzKgLGz6kGQc&Signature=3%2BPS9QtPKqy2Zi6kHkI1jZPXFd8%3D&response-content-disposition=attachment%3B%20'
!unzip -q -n weather.round1.train.gt.2019-2021.zip -d groundtruth
!unzip -q -n weather.round1.test.zip -d test
# 解压两个数据集

其中,由于主办方用的是阿里的oss,地址会定期变,需要用最新的下载指令
如何获取最新地址:
1.到比赛官网,点击这两个数据集的下载按钮(不用真等着下完!)
http://competition.sais.com.cn/competitionDetail/532234/competitionData
在这里插入图片描述
2.然后到浏览器的下载页面,右键点击地址,复制文件下载地址(这里以edge浏览器为例)
在这里插入图片描述
3.然后替换对应文件的旧下载地址
在这里插入图片描述
这样就能使用最新的下载地址下载数据集啦!

2.导入包函数

import os
import pandas as pd
import xarray as xr
# 用于处理多维数组,特别适合气象、海洋和气候数据的处理和分析。
from torch.utils.data import Dataset, DataLoader
# PyTorch 中用于构建和加载数据集的模块,帮助高效地管理和加载训练数据。

3.数据集路径配置

# path config
feature_path = 'feature' #自定义路径并修改为自己的路径
gt_path = 'groundtruth' #自定义路径并修改为自己的路径
years = ['2021']
fcst_steps = list(range(1, 73, 1))
# 定义了一个范围为1到72的列表,步长为1,通常用于表示预测步骤(forecast steps)。

数据集路径配置设置
比赛的数据部分分为数据特征数据真值两部分,数据特征是模型训练的输入,数据真值是模型训练的标签
其中,数特征部分 输入的路径目录下包含年份文件夹。
例如示例给出的 “输入路径(feature)/2021/…” 各年份文件夹下包含从官网下载的压缩包(e.g.weather.round1.train.ft.2021.1.zip) 解压后文件夹下有不同时段的数据文件夹(e.g. 20210101-00), 内部包含6个nc文件, 是从伏羲大模型中获取的从第6小时到第72小时的数据。
数据真值部分输入的路径目录下包含3个年份的.nc数据, 其中选择哪些年份的特征数据作为输入, 就在years中添加哪些年份。
fcst_steps指预测的时间步长, 从第1小时到第72小时, 间隔为1小时

4.其它数据集操作

Feature类和GroundTruth类是数据集的定义,分别用于处理特征数据和地面真实值(Ground Truth)数据,方便后续自定义数据集和数据加载类, 方便训练时取数据。

# Feature部分
class Feature:
    def __init__(self):
        self.path = feature_path
        self.years = years
        self.fcst_steps = fcst_steps
        self.features_paths_dict = self.get_features_paths()
        #  调用 get_features_paths() 方法获取特征数据的路径字典。

    def get_features_paths(self): # 获取特征数据路径的方法。
        init_time_path_dict = {}
        for year in self.years:
            init_time_dir_year = os.listdir(os.path.join(self.path, year))
            for init_time in sorted(init_time_dir_year):
                init_time_path_dict[pd.to_datetime(init_time)] = os.path.join(self.path, year, init_time)
        return init_time_path_dict
# 创建一个空的字典 init_time_path_dict。遍历每个年份的目录,获取初始时间的文件夹。将每个初始时间的路径存入字典中,键是转换为 pd.Timestamp 类型的初始时间,值是对应的路径。

    def get_fts(self, init_time):
        return xr.open_mfdataset(self.features_paths_dict.get(init_time) + '/*').sel(lead_time=self.fcst_steps).isel(
            time=0)
 # 使用 xr.open_mfdataset() 打开多个文件数据集,选择特定的预测步长(lead_time)和时间索引(time=0)
    
# GroundTruth部分
class GT:
    def __init__(self):
        self.path = gt_path
        self.years = years
        self.fcst_steps = fcst_steps
        self.gt_paths = [os.path.join(self.path, f'{year}.nc') for year in self.years] #  根据年份创建地面真实值数据的路径列表。
        self.gts = xr.open_mfdataset(self.gt_paths)  # 打开地面真实值数据集。

    def parser_gt_timestamps(self, init_time):
        return [init_time + pd.Timedelta(f'{fcst_step}h') for fcst_step in self.fcst_steps]

    def get_gts(self, init_time):

        return self.gts.sel(time=self.parser_gt_timestamps(init_time))

5.mydataset类

mydataset类的定义, 整合了加载特征和特征对应真值的功能, 方便后续训练时取数据。

# 构建Dataset部分
class mydataset(Dataset):
    def __init__(self):
        self.ft = Feature()
        self.gt = GT()
        self.features_paths_dict = self.ft.features_paths_dict   # 获取特征数据路径字典
        self.init_times = list(self.features_paths_dict.keys())   # 从特征数据路径字典中获取所有初始时间,作为一个列表存储。

    def __getitem__(self, index):
        init_time = self.init_times[index]
        ft_item = self.ft.get_fts(init_time).to_array().isel(variable=0).values	# 使用 Feature 类中的 get_fts 方法获取特定初始时间的特征数据。将 xarray.Dataset 转换为 xarray.DataArray,再使用 isel 方法选择第一个变量(variable=0),然后将其转换为 NumPy 数组。
        print(type(ft_item))
        gt_item = self.gt.get_gts(init_time).to_array().isel(variable=0).values # 使用 GT 类中的 get_gts 方法获取特定初始时间的地面真实值数据。与 ft_item 类似的处理过程,将数据转换为 NumPy 数组。
        print(type(gt_item))
        return ft_item, gt_item

    def __len__(self):
        return len(list(self.init_times))

6.查看数据数量

前五步已经完成了数据预处理加载的相关类和函数的准备, 这里可以通过实例化mydataset类来查看数据数量,同时完成数据集的构建后,可以通过DataLoader来查看数据集的数据。

# 可以查看一下已经构建的dataset
# define dataset
my_data = mydataset()
print('sample num:', mydataset().__len__())
train_loader = DataLoader(my_data, batch_size=1, shuffle=True) # 指定了每个批次的样本数量为1,这意味着每次迭代从数据集中取出一个样本。在每个 epoch 开始时打乱数据集,这有助于训练过程中更好地随机化数据顺序,提高模型的泛化能力。

7.构建模型

完成了数据的准备工作, 接下来就是构建模型的部分。Model这个类,对模型进行定义,方便后续训练时调用。这里以一个简单的只有一个卷积层的网络为例。在本次比赛中, 输入数据维度是(1, 24, 72, W, H),输出数据维度是(1, 72, W, H) 可以在赛题中查看。

# 模型构建部分
import torch.nn as nn
class Model(nn.Module):
    def __init__(self, num_in_ch, num_out_ch):
        super(Model, self).__init__()  # 调用父类 nn.Module 的构造函数。
        self.conv1 = nn.Conv2d(num_in_ch, num_out_ch, 3, 1, 1)

    def forward(self, x):
        B, S, C, W, H = tuple(x.shape)
        x = x.reshape(B, -1, W, H)   # 这里 -1 表示自动计算该维度大小。
        out = self.conv1(x)
        out = out.reshape(B, S, W, H)
        return out

# define model
in_varibales = 24
in_times = len(fcst_steps)
out_varibales = 1
out_times = len(fcst_steps)
input_size = in_times * in_varibales
output_size = out_times * out_varibales
model = Model(input_size, output_size).cuda()

8.损失函数

定义模型的损失函数部分, 用于模型训练做反向传播。

# define loss
loss_func = nn.MSELoss() 

9.模型训练

模型训练部分

import numpy as np
import torch
# from tqdm import tqdm
# Train the model
num_epochs = 1
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)

# for epoch in tqdm(range(num_epochs)):
for epoch in range(num_epochs):
    for index, (ft_item, gt_item) in enumerate(train_loader):
        ft_item = ft_item.cuda().float()
        gt_item = gt_item.cuda().float()
        print(type(ft_item))
        print(type(gt_item))
        
        # Forward pass
        output_item = model(ft_item)
        loss = loss_func(output_item, gt_item)
        
        # Backward and optimize
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        
        # Print the loss for every 10 steps
        if (index+1) % 10 == 0:
            print(f"Epoch [{epoch+1}/{num_epochs}], Step [{index+1}/{len(train_loader)}], Loss: {loss.item():.4f}")

# Save the model weights
torch.save(model.state_dict(), 'model_weights.pth')

10.模型推理

模型推理部分,通过加载模型使用测试数据作为输入,得到预测结果。其中test_data_path需要给出从下载测试数据解压后的目录路径。

# Inference
# Load the model weights
model.load_state_dict(torch.load('model_weights.pth'))
model.eval()
import os

test_data_path = "test/weather.round1.test"
os.makedirs("./output", exist_ok=True)
for index, test_data_file in enumerate(os.listdir(test_data_path)):
    test_data = torch.load(os.path.join(test_data_path, test_data_file))
    test_data = test_data.cuda().float()
    
    # Forward pass
    output_item = model(test_data)
    
    # Print the output shape
    print(f"Output shape for sample {test_data_file.split('.')[0]}: {output_item.shape}")# 打印当前样本的输出形状。
    
    # Save the output
    output_path = f"output/{test_data_file}"
    torch.save(output_item.cpu(), output_path)
    # Load the model weights
    model.load_state_dict(torch.load("model_weights.pth"))

机器学习

机器学习是人工智能的一个分支,它使计算机系统利用数据来不断改进性能,而无需进行明确的编程。通俗来说就是, 机器学习像一个学生, 通过给定的教材, 不断地学习教材内容,最终可以在期末考试或者综合实践中取得优异的成绩。
核心思想:通过算法和统计模型,机器学习允许计算机从经验中学习,识别模式,并做出预测或决策

  • 监督学习:算法从标记的训练数据中学习,这些数据包含了输入和期望的输出。
  • 无监督学习:算法处理未标记的数据,试图找出数据中的结构和模式。
    同时, 通过任务的输出是否离散, 机器学习的任务又可以划分为分类与回归。
    在这里插入图片描述

深度学习

深度学习则是机器学习中神经网络算法的进阶版。神经网络算法通过模拟人脑神经元的信息传递,逐层递进, 从而形成一个机器学习模型,而深度学习有着更深的层数, 有对大规模数据(例如上百万级)更好的学习效果,这个特点使得深度学习在数据量暴增的时代脱颖而出。
神经网络示意图如下:
在这里插入图片描述

pytorch

PyTorch是由Meta AI(Facebook)人工智能研究小组开发的一种基于Lua编写的Torch库的Python实现的深度学习库,目前被广泛应用于学术界和工业界。通过pytroch, 可以自由的搭建神经网络模型, 使之适配我们所需要的任务。
在baseline代码中,有几个工具类十分重要, 构建他们的过程, 都少不了pytorch的帮助

  1. 构建数据集的类Dataset
  2. 数据加载类的Dataloader
  3. 定义模型的类Model
    pytorch是一个非常好用的工具, 以便自由的构建我们的模型、数据集。可以更方便的尝试各种网络模型或者优化方法,同时又不需要大量的重复编程实现;另外, pytorch对GPU硬件有很好的支持, 通过GPU对模型训练进行加速, 可以节约大量的时间开销。可以说, 作为一款深度学习框架, pytorch目前在学术界和工业界都有着极高的地位。

如何使用深度学习实现降水预测模型

降水预测模型, 是一类时间序列相关的问题, 是一个有标注的监督学习的回归任务, 是使用在时间序列上前一部分的数据来预测后一部分的数据。通俗来说, 时间序列预测模型目的构建一个全时段可用的时间序列函数, 根据输入可以精准的得到目的的输出, 比如本次赛题中的降水预测模型。
那么我们如何去搭建一个预测模型呢?

  1. 首先我们需要做数据处理, 如果打开下载后的数据文件我们可以看到, 里面有feature特征文件和groundtruth真值文件, 因此我们首先要建立对应feature和groundtruth数据之间的关系, 这可以从baseline里看到具体的构建方法。
  2. 接着, 如果把降水预测模型看作一个函数, 我们需要尽可能找到一个最好拟合降水预测过程的函数。这时, 对数据有着良好拟合效果的深度学习就派上了用场:通过pytorch, 我们可以搭建神经网络, 尽可能去好的在我们的数据上做拟合, 通过一系列尝试我们就得到了拟合效果最好的模型。
  3. 最后, 我们需要在测试数据上验证模型的效果。
    大致通过这三步, 一个简单的预测模型就可以被我们搭建起来了。

在这里插入图片描述
回归任务示例
在这里插入图片描述
多元线性回归

总结

通过本次的学习,已经对搭建一个降水预测模型有了初步的了解, 对之前尝试的baseline也有了大致的认识, 明白了搭建一个降水预测模型的步骤是怎样的;同时, 也对一些基本的机器学习和深度学习知识, pytorch基础有了相关的了解,为之后的提升扫清了障碍。

参考文献

从零入门 AI for Science(AI+气象)
第二届世界科学智能大赛地球科学赛道:AI极端降水预报
【第二届世界科学智能大赛地球科学赛道:AI极端降水预报】FAQ

  • 13
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值