1.比赛资料
比赛名称:第二届世界科学智能大赛地球科学赛道:AI极端降水预报
官网连接:上海科学智能研究院
环境:https://www.modelscope.cn/my/mynotebook/preset
2.Task1 逐行解释代码
2.1Terminal环境安装
git lfs install
git clone https://www.modelscope.cn/datasets/Datawhale/AICamp_earth_baseline.git
这两行代码是用于Git版本控制系统的命令,通常用于从远程仓库克隆代码库到本地。
git lfs install
- 这条命令是用于初始化Git Large File Storage(LFS)的。
Git LFS是一个Git扩展,用于处理大型文件。
它允许你像处理小文件一样处理大文件,例如视频、图片或其他大型二进制文件。
install
命令会设置Git LFS,使其在当前仓库中可用。
git clone https://www.modelscope.cn/datasets/Datawhale/AICamp_earth_baseline.git
- 这是
git clone
命令,用于克隆远程Git仓库到本地。
- 这是
https://www.modelscope.cn/datasets/Datawhale/AICamp_earth_baseline.git
是远程仓库的URL地址。
当你执行这个命令时,Git会从该URL下载仓库的所有文件和历史记录到本地目录,
目录名称默认为仓库名,即AICamp_earth_baseline
。
请注意,实际执行这些命令之前,你需要确保你的计算机上已经安装了Git和Git LFS,
并且你有权限访问指定的远程仓库。
2.2安装数组处理库
在运行环境中安装对应的库,并解压数据集
执行命令即可
!pip install xarray[complete]
这行代码是Python的包管理工具pip的命令,用于安装一个名为xarray
的Python库,并指定了一个额外的选项[complete]
。下面是对这条命令的详细解释:
-
!
:这个感叹号在某些编程环境中(如Jupyter Notebook)用作命令行模式的指示符,表示接下来的内容应该作为命令行命令执行。如果你在标准的Python脚本或命令行环境中使用pip,你不需要这个感叹号。 -
pip
:是Python的包安装器,用于安装和管理Python包。 -
install
:这是pip的一个子命令,用于安装指定的包。 -
xarray[complete]
:指定了要安装的包名和额外的选项。xarray
是一个开源的、用于处理多维数组的Python库,特别适合处理N维数组,常用于地球科学和数据科学领域。[complete]
是一个额外的选项,表示安装xarray
时包括所有可选的依赖项,这通常意味着安装一些额外的库,这些库提供了额外的功能或优化性能。
执行这条命令后,pip会从Python包索引(PyPI)下载xarray
及其所有必要的依赖项,并安装到当前Python环境中。这确保了xarray
的所有功能都能正常使用。如果你只需要xarray
的基本功能,也可以省略[complete]
选项,仅安装核心包。
2.3解压数据集:训练集和测试集
!unzip -q -n weather.round1.train.gt.2019-2021.zip -d groundtruth
!unzip -q -n weather.round1.test.zip -d test
这两行代码是Unix-like系统的命令行指令,用于解压ZIP文件。下面是对每条命令的逐行解释:
-
!unzip -q -n weather.round1.train.gt.2019-2021.zip -d groundtruth
!
:在某些编程环境(如Jupyter Notebook)中,感叹号用于执行系统命令。unzip
:是一个用于解压ZIP文件的命令行工具。-q
:表示“quiet”模式,即安静模式,不显示解压过程中的详细信息。-n
:表示不覆盖已存在的文件。如果目标目录中已经存在与ZIP文件中同名的文件,unzip
命令将不会替换它们。weather.round1.train.gt.2019-2021.zip
:这是要解压的ZIP文件的名称。-d
:后面跟着的是解压后文件存放的目录。这里是groundtruth
,意味着解压后的文件将被放置在这个名为groundtruth
的目录中。
-
!unzip -q -n weather.round1.test.zip -d test
- 这条命令与第一条命令类似,只是解压的ZIP文件和目标目录不同。
weather.round1.test.zip
:这是另一个要解压的ZIP文件的名称。-d test
:指定了解压后文件存放的目录为test
。
执行这两条命令后,weather.round1.train.gt.2019-2021.zip
和weather.round1.test.zip
这两个ZIP文件将被解压到当前目录下的groundtruth
和test
目录中,且不会覆盖已存在的同名文件。如果你在标准的命令行环境中使用这些命令,可以去掉前面的感叹号。
2.4 导入运行所需要的库函数
import os
import pandas as pd
import xarray as xr
from torch.utils.data import Dataset, DataLoader
这段Python代码是导入模块的语句,用于在Python脚本或Jupyter Notebook中引入所需的库。下面是对每个导入语句的解释:
-
import os
- 这行代码导入了Python的标准库
os
,它提供了一种方便的方式来使用操作系统依赖的功能,如文件路径操作、环境变量访问等。
- 这行代码导入了Python的标准库
-
import pandas as pd
- 这行代码导入了
pandas
库,并将其别名设置为pd
。pandas
是一个强大的数据分析和操作库,广泛用于数据处理和分析任务,特别是处理表格数据(如CSV文件)。
- 这行代码导入了
-
import xarray as xr
- 这行代码导入了
xarray
库,并将其别名设置为xr
。xarray
是一个用于处理多维数组的库,特别适合于处理具有标签的N维数组,常用于地球科学、气象学等领域。
- 这行代码导入了
-
from torch.utils.data import Dataset, DataLoader
- 这行代码从
torch.utils.data
模块导入了Dataset
和DataLoader
类。 torch.utils.data
是PyTorch框架的一部分,用于数据加载和批处理。Dataset
是一个抽象类,用于定义自定义数据集。它需要你实现__len__
方法(返回数据集中的样本数量)和__getitem__
方法(根据索引获取数据集中的样本)。DataLoader
是一个迭代器,用于批量加载数据集,支持自动加载、自动打乱(如果设置了shuffle=True
)和多线程加载。
- 这行代码从
这些导入的库和类通常用于数据科学、机器学习和深度学习项目中,用于数据处理、分析以及模型训练的数据准备。
2.5 数据集路径配置设置
比赛的数据部分分为数据特征和数据真值两部分,数据特征是模型训练的输入,数据真值是模型训练的标签
其中数据特征部分
输入的路径目录下包含年份文件夹
例如示例给出的 “输入路径/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小时
# path config
feature_path = 'feature'
gt_path = 'groundtruth'
years = ['2021']
fcst_steps = list(range(1, 73, 1))
这段Python代码是设置路径配置和一些变量的语句,通常用于定义数据文件的存储路径和一些分析或模型训练过程中需要的参数。下面是对每行代码的解释:
-
# path config
- 这是一个注释行,用于说明接下来的几行代码是关于路径配置的。
-
feature_path = 'feature'
- 这行代码定义了一个名为
feature_path
的变量,其值为字符串'feature'
。这通常用于指定存放特征数据的目录路径。
- 这行代码定义了一个名为
-
gt_path = 'groundtruth'
- 这行代码定义了一个名为
gt_path
的变量,其值为字符串'groundtruth'
。这通常用于指定存放地面真实数据(Ground Truth)的目录路径。
- 这行代码定义了一个名为
-
years = ['2021']
- 这行代码创建了一个名为
years
的列表,其中只包含一个元素'2021'
。这个列表用于指定分析或模型训练所使用的年份数据。
- 这行代码创建了一个名为
-
fcst_steps = list(range(1, 73, 1))
- 这行代码首先使用
range
函数生成一个从1到72的整数序列(因为range(1, 73, 1)
的结束索引是不包含的,即73不包括在内),然后使用list
函数将这个序列转换成一个列表,赋值给变量fcst_steps
。这个列表可能用于表示预测的时间步长,例如在气象预测中,可能表示从1小时到72小时的每个小时的预测。
- 这行代码首先使用
这些变量和配置通常在数据处理或模型训练脚本的开始部分设置,以便于在脚本的其他部分引用这些路径和参数。
2.6 Feature类和GroundTruth类是数据集的定义
方便后续自定义数据集和数据加载类, 方便我们训练时取数据
# 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()
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
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)
# 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))
这段Python代码定义了两个类:Feature
和GT
,它们用于处理特征数据和地面真实数据。下面是对每个类及其方法的详细解释:
Feature
类
- 这个类用于处理特征数据。
__init__
方法
- 初始化
Feature
类的实例,设置特征数据的路径、年份、预测步长,并调用get_features_paths
方法来获取特征数据的路径字典。
get_features_paths
方法
- 遍历指定年份,列出每个年份目录下的初始化时间点,并为每个时间点生成一个路径字典。这个字典将初始化时间点映射到其对应的特征数据路径。
get_fts
方法
- 根据给定的初始化时间
init_time
,打开对应的特征数据集,并选择特定的预测步长和时间点。这里使用了xarray
库的open_mfdataset
方法来打开多文件数据集,并使用sel
和isel
方法来选择数据。
GT
类
- 这个类用于处理地面真实数据。
__init__
方法
- 初始化
GT
类的实例,设置地面真实数据的路径、年份、预测步长,并构建包含所有年份数据文件路径的列表,然后打开这些数据集。
parser_gt_timestamps
方法
- 根据给定的初始化时间
init_time
和预测步长列表,生成一个包含所有预测时间点的列表。这里使用了pandas
库的Timedelta
来增加时间。
get_gts
方法
- 根据给定的初始化时间
init_time
,选择对应的时间点数据。这里使用了xarray
库的sel
方法来选择时间维度上的数据。
代码示例解释
- 这两个类通过封装数据加载和处理的逻辑,使得数据的获取更加模块化和可重用。
os.listdir
用于列出目录中的文件和子目录。os.path.join
用于拼接文件路径。pd.to_datetime
将字符串转换为pandas
的Timestamp
对象,便于后续处理。xarray.open_mfdataset
用于打开多个NetCDF格式的数据文件作为一个数据集。.sel
和.isel
是xarray
中用于选择数据的方法,分别用于选择数据的特定维度和索引。
注意事项
- 这段代码中有几个变量(
feature_path
、gt_path
、years
、fcst_steps
)在类定义之前已经定义,它们被用作类的属性。 - 这段代码假设特征数据和地面真实数据都是以NetCDF格式存储,并且可以通过
xarray
库进行读取。 - 代码中的注释较少,实际使用时可能需要添加更多的注释来提高代码的可读性。
2.7 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
print(type(ft_item))
gt_item = self.gt.get_gts(init_time).to_array().isel(variable=0).values
print(type(gt_item))
return ft_item, gt_item
def __len__(self):
return len(list(self.init_times))
这段Python代码定义了一个名为 mydataset
的类,它继承自 PyTorch 的 Dataset
类。这个类用于构建一个自定义的数据集,通常用于深度学习模型的训练和评估。下面是对类及其方法的详细解释:
mydataset
类
- 这个类是用于封装特征数据和地面真实数据,使其可以被 PyTorch 的
DataLoader
使用。
__init__
方法
- 初始化
mydataset
类的实例。 - 创建
Feature
和GT
类的实例,分别用于处理特征数据和地面真实数据。 - 从
Feature
实例中获取特征数据路径字典features_paths_dict
。 - 获取所有初始化时间点的列表
init_times
,这些时间点将用于索引数据集中的样本。
__getitem__
方法
- 这是
Dataset
类的一个特殊方法,用于按索引获取数据集中的单个样本。 - 根据传入的索引
index
,从init_times
中获取对应的初始化时间init_time
。 - 使用
Feature
实例的get_fts
方法获取特征数据ft_item
,并通过to_array()
、isel()
和values
进一步处理数据,使其成为一个一维数组。 - 使用
GT
实例的get_gts
方法获取地面真实数据gt_item
,同样进行处理。 - 打印
ft_item
和gt_item
的类型,以确保它们是预期的数据类型。 - 返回一个元组,包含特征数据和地面真实数据。
__len__
方法
- 这是
Dataset
类的另一个特殊方法,用于返回数据集中的样本数量。 - 返回
init_times
列表的长度。
代码示例解释
mydataset
类通过封装数据加载逻辑,使得数据可以方便地用于 PyTorch 的模型训练和评估。__getitem__
方法中的print(type(ft_item))
和print(type(gt_item))
用于调试,检查返回数据的类型是否正确。- 这个类可以与 PyTorch 的
DataLoader
配合使用,以实现数据的批量加载、打乱、多线程加载等功能。
注意事项
- 这段代码假设
Feature
和GT
类的get_fts
和get_gts
方法返回的数据可以直接转换为一维数组。在实际使用中,可能需要根据具体的数据结构进行调整。 isel(variable=0)
假设数据集中只有一个变量,如果数据集中有多个变量,可能需要调整索引。- 代码中的打印语句主要用于调试,实际部署时可能需要移除或替换为更合适的日志记录方式。
2.8实例化mydataset类
前五步已经完成了数据预处理加载的相关类和函数的准备,
这里我们可以通过实例化mydataset类来查看数据数量
同时完成数据集的构建后, 我们可以通过DataLoader来查看数据集的数据
# 可以查看一下已经构建的dataset
# define dataset
my_data = mydataset()
print('sample num:', mydataset().__len__())
train_loader = DataLoader(my_data, batch_size=1, shuffle=True)
这段Python代码演示了如何使用之前定义的 mydataset
类来创建一个数据集实例,并使用 PyTorch 的 DataLoader
来加载数据。下面是对代码的逐行解释:
-
# 可以查看一下已经构建的dataset
- 这是一行注释,说明接下来的代码将展示如何查看构建的数据集。
-
# define dataset
- 这也是一行注释,表示定义数据集的开始。
-
my_data = mydataset()
- 这行代码创建了
mydataset
类的一个实例,命名为my_data
。
- 这行代码创建了
-
print('sample num:', mydataset().__len__())
- 这行代码打印数据集中的样本数量。首先,它调用
mydataset()
来创建mydataset
类的一个新实例,然后调用该实例的__len__
方法来获取样本数量,并打印出来。
- 这行代码打印数据集中的样本数量。首先,它调用
-
train_loader = DataLoader(my_data, batch_size=1, shuffle=True)
- 这行代码使用
DataLoader
类来创建一个数据加载器train_loader
,它将用于批量加载my_data
数据集中的数据。 batch_size=1
表示每个批次加载一个样本。这个值可以根据需要调整,例如,增加到更大的数值以提高训练效率。shuffle=True
表示在每个epoch开始时,数据将被打乱。这有助于模型训练时的泛化能力。
- 这行代码使用
代码示例解释
- 通过创建
mydataset
类的实例,你可以访问数据集中的所有样本。 - 使用
DataLoader
可以方便地实现数据的批量加载和打乱,这对于训练深度学习模型非常有用。 batch_size
和shuffle
参数可以根据你的具体需求进行调整。
注意事项
- 在实际使用中,你可能需要根据你的硬件配置和模型需求来调整
batch_size
的大小。 - 如果数据集很大,打乱数据可能会增加内存的使用,因为
DataLoader
需要在内存中存储整个数据索引。 - 打印样本数量是一个快速检查数据集大小的方法,但在实际训练中,你可能不需要打印这个信息,除非需要调试或验证数据集的大小。
2.9
完成了数据的准备工作, 接下来就是构建模型的部分
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__()
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)
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()
这段Python代码定义了一个简单的卷积神经网络模型,并使用PyTorch框架进行实现。下面是对代码的逐行解释:
模型构建部分
-
import torch.nn as nn
- 导入PyTorch的神经网络模块
nn
,这个模块包含了构建神经网络所需的层和函数。
- 导入PyTorch的神经网络模块
-
定义
Model
类,继承自nn.Module
:- 这是一个自定义的神经网络模型类,它继承自PyTorch的
nn.Module
基类。
- 这是一个自定义的神经网络模型类,它继承自PyTorch的
-
Model
类的__init__
方法:- 在类的构造函数中,首先调用
super()
方法来初始化基类。 - 定义一个二维卷积层
conv1
,它接受输入通道数num_in_ch
,输出通道数num_out_ch
,卷积核大小为3x3,步长为1,填充为1。
- 在类的构造函数中,首先调用
-
Model
类的forward
方法:- 这个方法定义了数据通过网络的前向传播路径。
x
是输入张量,其形状被分解为批次大小B
,序列长度S
,通道数C
,宽度W
和高度H
。- 输入数据被重新塑形以匹配卷积层的期望形状。
- 卷积层
conv1
应用于输入数据。 - 输出张量再次被重塑以恢复原始的序列形状。
-
定义模型:
- 设置输入变量数
in_varibales
,输入时间步长in_times
,输出变量数out_varibales
和输出时间步长out_times
。 - 计算输入和输出的总尺寸
input_size
和output_size
。 - 创建
Model
类的实例model
,将输入和输出尺寸作为参数传递。 - 使用
.cuda()
将模型移动到GPU上进行加速(如果可用)。
- 设置输入变量数
注意事项
- 这个模型是一个非常基础的卷积神经网络,只包含一个卷积层。在实际应用中,你可能需要添加更多的层(如激活层、池化层、全连接层等)以及调整模型结构以适应特定任务。
forward
方法中的重塑操作假设输入数据的形状是(B, S, C, W, H)
,这可能需要根据你的具体数据形状进行调整。- 模型的输出尺寸
output_size
被设置为等于输入尺寸,这可能不是所有情况的理想选择。你可能需要根据任务需求调整输出层的尺寸或添加额外的层来改变输出的维度。 - 使用
.cuda()
将模型和数据移动到GPU上可以显著加速训练过程,但需要确保你的环境支持CUDA。如果你的环境不支持CUDA,可以省略这个调用。
2.10 定义模型的损失函数部分, 用于模型训练做反向传播
# define loss
loss_func = nn.MSELoss()
在这段代码中,定义了一个损失函数,用于在训练神经网络模型时评估预测值与实际值之间的差异。以下是对代码的解释:
-
import torch.nn as nn
:首先,代码导入了PyTorch的神经网络模块nn
,这是使用PyTorch定义模型层和损失函数的标准步骤。 -
loss_func = nn.MSELoss()
:这行代码创建了一个均方误差(Mean Squared Error, MSE)损失函数的实例,并将其赋值给变量loss_func
。MSE损失函数是回归问题中常用的损失函数之一,它计算预测值与目标值之间差异的平方的平均值。
均方误差损失函数的公式定义如下:
其中:
- ( N ) 是样本数量。
- ( y_i ) 是第( i )个样本的真实值。
- ( \hat{y}_i ) 是第( i )个样本的预测值。
使用场景
loss_func
对象现在可以用于神经网络的训练过程中。在每个训练批次中,模型的预测输出和实际目标值将被传递给这个损失函数,以计算损失值。这个值通常被用来通过反向传播更新模型的权重。
注意事项
- 均方误差损失函数适用于连续的输出值,例如在回归任务中。如果你的任务是分类问题,可能需要使用不同的损失函数,如交叉熵损失(Cross-Entropy Loss)。
- PyTorch提供了多种损失函数,可以通过
nn
模块访问,以适应不同类型的任务需求。 - 损失函数的选择取决于具体问题和模型的输出,因此在选择损失函数时应考虑问题的性质和模型的设计。
2.11 模型训练部分
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')
这段Python代码演示了如何使用PyTorch框架训练一个神经网络模型,并在训练结束后保存模型权重。以下是对代码的逐行解释:
-
导入所需的库:
import numpy as np
:导入NumPy库,一个用于科学计算的Python库。import torch
:导入PyTorch库,用于构建和训练神经网络。# from tqdm import tqdm
:这行代码被注释掉了,它本意是导入tqdm
库,用于显示训练进度条。
-
定义训练参数和优化器:
num_epochs = 1
:设置训练的轮数(epoch)为1。optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
:创建一个Adam优化器,用于模型的参数更新。学习率(lr)设置为0.001。
-
训练循环:
- 外层循环遍历每个epoch。
- 内层循环遍历
DataLoader
(train_loader
)中的每个批次。
-
数据处理:
ft_item = ft_item.cuda().float()
和gt_item = gt_item.cuda().float()
:将特征数据和目标数据转换为浮点数并移动到GPU上。
-
打印数据类型:
print(type(ft_item))
和print(type(gt_item))
:打印特征数据和目标数据的类型,用于调试。
-
前向传播:
output_item = model(ft_item)
:通过模型进行前向传播,得到预测输出。
-
计算损失:
loss = loss_func(output_item, gt_item)
:使用之前定义的损失函数计算预测输出和目标数据之间的损失。
-
反向传播和优化:
optimizer.zero_grad()
:清除之前的梯度,为新的迭代准备。loss.backward()
:计算损失相对于模型参数的梯度。optimizer.step()
:根据梯度更新模型参数。
-
打印损失信息:
- 如果当前批次索引除以10的余数为0,打印当前的epoch、批次索引和损失值。
-
保存模型权重:
torch.save(model.state_dict(), 'model_weights.pth')
:训练结束后,保存模型的权重到文件model_weights.pth
。
注意事项
- 这段代码假设模型
model
和DataLoader
train_loader
已经被定义。 - 代码中的
print
语句用于调试和监控训练过程,实际部署时可能需要调整或移除。 - 损失值的打印频率(每10个批次打印一次)可以根据需要调整。
- 使用
.cuda()
确保数据和模型都在GPU上运行,如果环境不支持CUDA,应该移除这个调用或使用.cpu()
。 - 保存模型权重前,确保模型已经在正确的设备上(CPU或GPU)。
- 如果使用
tqdm
库,可以提供更友好的训练进度条,但需要取消注释并适当修改循环结构。
2.12 模型推理部分
通过加载模型使用测试数据作为输入, 得到预测结果
其中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中进行模型推理(Inference),包括加载模型权重、设置模型为评估模式、处理测试数据、执行前向传播、打印输出形状、保存输出结果,并在处理完所有测试数据后再次加载模型权重。以下是对代码的逐行解释:
-
model.load_state_dict(torch.load('model_weights.pth'))
:- 加载之前训练并保存的模型权重到当前模型中。
-
model.eval()
:- 将模型设置为评估模式,这会关闭特定于训练阶段的层,如Dropout。
-
import os
:- 导入Python的操作系统接口,用于文件和目录操作。
-
test_data_path = "test/weather.round1.test"
:- 设置测试数据的路径。
-
os.makedirs("./output", exist_ok=True)
:- 创建一个名为
output
的目录来存储推理结果,如果目录已存在则不会抛出错误。
- 创建一个名为
-
循环遍历测试数据文件:
for index, test_data_file in enumerate(os.listdir(test_data_path))
:- 遍历
test_data_path
目录下的所有文件。
- 遍历
-
加载测试数据:
test_data = torch.load(os.path.join(test_data_path, test_data_file))
:- 加载单个测试数据文件。
-
数据处理:
test_data = test_data.cuda().float()
:- 将测试数据转换为浮点数并移动到GPU上。
-
前向传播:
output_item = model(test_data)
:- 使用模型进行前向传播,得到推理输出。
-
打印输出形状:
print(f"Output shape for sample {test_data_file.split('.')[0]}: {output_item.shape}")
:- 打印每个测试样本的输出形状。
-
保存输出:
output_path = f"output/{test_data_file}"
:- 设置输出文件的路径。
torch.save(output_item.cpu(), output_path)
:- 将推理输出从GPU移动到CPU,并保存到文件。
-
再次加载模型权重:
model.load_state_dict(torch.load("model_weights.pth"))
:- 在处理完所有测试数据后,再次加载模型权重。
注意事项
- 代码中假设模型权重文件
model_weights.pth
位于当前工作目录下。 - 代码中的
.cuda()
调用假设你有可用的CUDA设备,如果环境不支持CUDA,应该使用.cpu()
。 - 模型权重在循环结束后再次加载可能是不必要的,除非在循环中有修改模型权重的操作。
- 保存输出时,确保输出文件的路径正确,并且当前用户有写入权限。
- 如果测试数据集很大,可能需要考虑内存使用情况,避免一次性将所有数据加载到内存中。
- 代码中的输出路径硬编码为
output/
,可能需要根据实际需求调整。
2.13 所有内容压缩成一个ZIP格式的压缩文件
!zip -r output.zip output
这行命令是Unix-like系统的命令行指令,用于将output
目录中的所有内容压缩成一个ZIP格式的压缩文件。下面是对这条命令的详细解释:
-
!
:在某些编程环境(如Jupyter Notebook)中,感叹号用于执行系统命令。如果你在标准的命令行环境中使用这条命令,你不需要这个感叹号。 -
zip
:是一个用于创建ZIP格式压缩文件的命令行工具。 -
-r
:这个选项告诉zip
命令递归地压缩目录,即包括指定目录及其子目录中的所有内容。 -
output.zip
:这是输出的ZIP文件的名称,压缩后的结果将保存为这个文件。 -
output
:这是要压缩的目录的名称。
执行这条命令后,当前目录下名为output
的目录及其所有子目录和文件将被压缩到一个名为output.zip
的ZIP文件中。如果output.zip
文件已经存在,它会被覆盖;如果不存在,将创建一个新的ZIP文件。
注意事项
- 确保你有足够的磁盘空间来存储压缩文件。
- 如果
output
目录包含大量文件或非常大的文件,压缩过程可能需要一些时间。 - 如果你希望在压缩过程中保留文件的权限和属性,可以使用
-x
选项来排除特定文件或目录。 - 如果你希望压缩文件包含存储的相对路径,可以使用
-j
选项来排除目录路径。
3.正式了解一下赛题!
本次学习活动的赛题“AI极端降水预报挑战赛”是一个典型的时间序列预测问题
时间序列预测问题是指涉及使用历史数据来预测未来值。这种问题在许多领域都有应用,如金融市场预测、销售预测、天气预报等。此类问题是典型的有监督的回归问题。解决此类问题, 我们要善于发现其中内在数据的相关性, 尤其是在时间、周期上呈现出的特征, 加以特征工程为我们所用。
- 导入库:首先,代码导入了需要用到的库,包括 torch 和处理气象数据必要的 xarray,用于处理结构数据的pandas和常用操作系统库os
- 数据集构建:代码通过使用 class Feature 类和class GT类定义了从气象.nc文件中读取数据,同时通过class Dataset 类将训练数据和对应标签建立起对应关系, 最后使用torch.utils.data中的DataLoader定义数据加载工具, 方便我们在训练过程中获取数据。
- 定义模型和使用的损失函数:
- 定义了只含有一层卷积的简单网络, 使用MSE作为损失函数, 特别注意模型的输入输出要根据赛题要求设计。
- 模型训练:
- 完成优化器和训练周期的定义后, 我们就可以开始训练模型以便在数据上得到一个拟合程度最好的训练模型,模型训练时不要忘了保存模型参数文件.pth
- 加载训练好的模型进行预测输出:
- 加载第4步中的训练参数以后, 需要用model.eval()将模型置于推理模式, 然后我们就有了一个拟合程度相对不错的降水预测模型, 再把测试数据输入, 就可以生成预测结果~
伪代码在这里:
# 1. 导入需要用到的相关库
import os
import torch
import pandas as pd
import xarray as xr
import torch.nn as nn
from torch.utils.data import Dataset, DataLoader
# 2. 定义数据集
path = "" # 配置路径的设置..
class Feature:
pass
class GT:
pass
class mydataset(Dataset):
def __init__(self):
...
def __getitem__(self, index):
# 获取训练数据的方法, 同时将训练数据和真值建立联系
...
def __len__(self):
#获取数据集长度的方法
...
my_data = mydataset() # 初始化dataset
train_loader = DataLoader(my_data, batch_size=1, shuffle=True) # 定义dataloader
# 3. 定义模型和损失函数
class Model(nn.Module):
# 模型初始化
def __init__(self, *args):
...
# 定义前向传播函数
def forward(self, *args):
...
# 模型具体输入输出定义
input_chnl = ...
# loss定义
loss = nn.MSELoss()
# 4. 模型训练
num_epochs = 1 # 定义模型训练轮数
optimizer = torch.optim.Adam(model.parameters(), lr=0.001) # 定义优化器
# 从dataloader中取数据训练
for epoch in range(num_epochs):
for index, (ft_item, gt_item) in enumerate(train_loader):
...
torch.save(model.state_dict(), "xxx.pth") # 保存模型参数
# 5. 模型推理
model.load_state_dict(torch.load('model_weights.pth')) # 加载模型
model.eval() # 将模型置于推理状态
test_data_path = "xxx"
# 模型推理
for index, test_data_file in enumerate(os.listdir(test_data_path)):
...
4. 关于PyTorch库和深度学习
Pandas学习推荐
Datawhale有一个开源教程项目叫 深入浅出PyTorch,链接如下
在线内容链接:https://datawhalechina.github.io/thorough-pytorch/
(如果大家想仔细研读的话,可以在学习过程中,依照其中的内容进行实践;
还可以多多在此处留言,也许夏令营后就会展开组队学习哟~)
深度学习学习材料推荐
Datawhale也有一个针对深度学习的开源导学项目叫 水很深的深度学习
开源项目地址: https://github.com/datawhalechina/unusual-deep-learning
大家在本次学习过程中,可以一边将上面推荐的材料作为字典,遇到问题时通过这些材料、大模型、搜索引擎,去翻阅查看,做到理论和实践的结合,真正理解这些理论知识的价值、以及究竟要如何在真实的问题场景中使用。
5.什么是机器学习, 什么是深度学习?
机器学习是人工智能的一个分支,它使计算机系统利用数据来不断改进性能,而无需进行明确的编程。
通俗来说就是, 机器学习像一个学生, 通过给定的教材, 不断地学习教材内容,最终可以在期末考试或者综合实践中取得优异的成绩。
核心思想:通过算法和统计模型,机器学习允许计算机从经验中学习,识别模式,并做出预测或决策。
- 监督学习:算法从标记的训练数据中学习,这些数据包含了输入和期望的输出。
- 无监督学习:算法处理未标记的数据,试图找出数据中的结构和模式。
同时, 通过任务的输出是否离散, 机器学习的任务又可以划分为分类与回归
深度学习则是机器学习中神经网络算法的进阶版。神经网络算法通过模拟人脑神经元的信息传递,逐层递进, 从而形成一个机器学习模型,而深度学习有着更深的层数, 有对**大规模数据(例如上百万级)**更好的学习效果,这个特点使得深度学习在数据量暴增的时代脱颖而出。
神经网络示意图如下:
6. 什么是pytorch?
PyTorch是由Meta AI(Facebook)人工智能研究小组开发的一种基于Lua编写的Torch库的Python实现的深度学习库,目前被广泛应用于学术界和工业界。通过pytroch, 我们可以自由的搭建神经网络模型, 使之适配我们所需要的任务。
在我们的baseline中,有几个工具类十分重要, 构建他们的过程, 都少不了pytorch的帮助
- 构建数据集的类Dataset
- 数据加载类的Dataloader
- 定义模型的类Model
pytorch是一个非常好用的工具, 以便我们自由的构建我们的模型、数据集,这让我们可以更方便的尝试各种网络模型或者优化方法, 同时又不需要大量的重复编程实现;另外, pytorch对GPU硬件有很好的支持, 通过GPU对我们的模型训练进行加速, 可以节约大量的时间开销。可以说, 作为一款深度学习框架, pytorch目前在学术界和工业界都有着极高的地位.
[] 对pytorch的具体了解, 请参考:https://datawhalechina.github.io/thorough-pytorch/
[] 如果对pytorch有着深入学习的想法, 强烈推荐官方社区: https://pytorch.org/community-blog
7.赛题初探, 如何使用深度学习实现搭建降水预测模型?
降水预测模型, 是一类时间序列相关的问题, 是一个有标注的监督学习的回归任务, 是使用在时间序列上前一部分的数据来预测后一部分的数据。通俗来说, 时间序列预测模型目的在构建一个全时段可用的时间序列函数, 根据输入可以精准的得到目的的输出, 比如本次赛题中的降水预测模型.
那么我们如何去搭建一个预测模型呢?
- 首先我们需要做数据处理, 如果打开下载后的数据文件我们可以看到, 里面有feature特征文件和groundtruth真值文件, 因此我们首先要建立对应feature和groundtruth数据之间的关系, 这可以从baseline里看到具体的构建方法.
- 接着, 如果把降水预测模型看作一个函数, 我们需要尽可能找到一个最好拟合降水预测过程的函数. 这时, 对数据有着良好拟合效果的深度学习就派上了用场:通过pytorch, 我们可以搭建神经网络, 尽可能去好的在我们的数据上做拟合, 通过一系列尝试我们就得到了拟合效果最好的模型.
- 最后, 我们需要在测试数据上验证模型的效果.
大致通过这三步, 一个简单的预测模型就可以被我们搭建起来了.
温馨提示:baseline中的代码仅下载了 weather.round1.train.gt.2019-2021.zip 和 weather.round1.test.zip文件,后续上分可能需要使用更多特征和数据,可在Notebook中通过如下命令下载,如果需要在命令行运行,去掉每个命令最开始的 ! 即可。
另外还可以使用 !axel -n 5 -o 命令实现更快捷的下载
!wget -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=1721852797&OSSAccessKeyId=LTAI5t7fj2oKqzKgLGz6kGQc&Signature=%2B4JoTbsP%2FQuqmG%2FZbWWH2oYZPRM%3D&response-content-disposition=attachment%3B%20'
!wget -O weather.round1.train.ft.2021.2.zip 'https://tianchi-race-prod-sh.oss-cn-shanghai.aliyuncs.com/file/race/documents/532234/bigFile/weather.round1.train.ft.2021.2.zip?Expires=1721852870&OSSAccessKeyId=LTAI5t7fj2oKqzKgLGz6kGQc&Signature=nHf8TSnRfFtcMDcaIjLG6HPh%2FvI%3D&response-content-disposition=attachment%3B%20'
!wget -O weather.round1.train.ft.2020.2.zip 'https://tianchi-race-prod-sh.oss-cn-shanghai.aliyuncs.com/file/race/documents/532234/bigFile/weather.round1.train.ft.2020.2.zip?Expires=1721852901&OSSAccessKeyId=LTAI5t7fj2oKqzKgLGz6kGQc&Signature=Q3ox8S1BH2O1iGlvlS73fqqUyfk%3D&response-content-disposition=attachment%3B%20'
!wget -O weather.round1.train.ft.2021.1.zip 'https://tianchi-race-prod-sh.oss-cn-shanghai.aliyuncs.com/file/race/documents/532234/bigFile/weather.round1.train.ft.2021.1.zip?Expires=1721852947&OSSAccessKeyId=LTAI5t7fj2oKqzKgLGz6kGQc&Signature=qpA4yqb6X5oBxF6JLkJaXi2RKPE%3D&response-content-disposition=attachment%3B%20'
!wget -O weather.round1.train.ft.2020.1.zip 'https://tianchi-race-prod-sh.oss-cn-shanghai.aliyuncs.com/file/race/documents/532234/bigFile/weather.round1.train.ft.2020.1.zip?Expires=1721852982&OSSAccessKeyId=LTAI5t7fj2oKqzKgLGz6kGQc&Signature=QTXWzcOMtwMhVThzo9oeOf7GdQQ%3D&response-content-disposition=attachment%3B%20'
!wget -O weather.round1.train.ft.2019.1.zip 'https://tianchi-race-prod-sh.oss-cn-shanghai.aliyuncs.com/file/race/documents/532234/bigFile/weather.round1.train.ft.2019.1.zip?Expires=1721853153&OSSAccessKeyId=LTAI5t7fj2oKqzKgLGz6kGQc&Signature=4gthkBT9KHya%2FIFwjyFIx69DN7o%3D&response-content-disposition=attachment%3B%20'
!wget -O weather.round1.train.ft.2019.2.zip 'https://tianchi-race-prod-sh.oss-cn-shanghai.aliyuncs.com/file/race/documents/532234/bigFile/weather.round1.train.ft.2019.2.zip?Expires=1721853188&OSSAccessKeyId=LTAI5t7fj2oKqzKgLGz6kGQc&Signature=egty%2BptJf5Xc2cjIOc3dmInuauA%3D&response-content-disposition=attachment%3B%20'
!wget -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=1721853230&OSSAccessKeyId=LTAI5t7fj2oKqzKgLGz6kGQc&Signature=AGbaVGl%2BC7EdWBlKKnOkcJ5hJu0%3D&response-content-disposition=attachment%3B%20'
8.上分思路
相信各位优秀的小伙伴们都已经完成了赛事速通,也获取到了第一个成绩, 恭喜各位~
那么接下来, 大家肯定对榜单上名列前茅的朋友们的方案十分感兴趣——他们是怎么做到的呢?
助教老师给大家一些小思路和方向, 大家可以先自由思考一下, 如何能获取到更优异的成绩呢.
-
数据
-
模型
-
参数设置
在后续课程中, 助教老师们将为大家揭示如何获取到更优异的成绩的秘诀,请各位期待!
也欢迎将自己的实验添加到放在打卡链接中, 我们助教团会评审大家的作业, 如果有让我们眼前一亮的作品, 就有机会成为优秀学习者~ -
在baseline的基础上, 你会调整哪些部分, 以获取到更高的分数?
-
baseline中数据处理部分, 是否遇到了某些问题?你认为可以在哪里做一下提升和改进?
-
模型训练部分,是否有哪些不合理或者需要提升的地方, 如果你来实现这一部分, 你会对哪里改进?