竞赛题目
官网地址
问题类型:时间序列预测问题。
基于历史气候观测和模式模拟数据,利用T时刻过去12个月(包含T时刻)的时空序列(气象因子),构建预测ENSO的深度学习模型,预测未来1-24个月的Nino3.4指数,如下图所示:
数据
东经 0°–360°,南纬 55°到北纬 60°-> 维度(24,72)
- 海平面温度(SST)
- 热含量异常(T300)
- 纬向风异常(Ua)
- 经向风异常(Va)
SODA数据:可以当成真实数据 100年
CMIP5/CMIP6:可以当成模拟数据(大气模型模拟) CMIP5: 151年 * 15 个模式=2265 140年 * 17 个模式=2380
Label: nino3.4指标
SODA_train、SODA_label、CMIP_train、CMIP_label
评估指标
评分细则说明:根据所提供的n个测试数据,对模型进行测试,得到n组未来1-24个月的序列选取对应预测时效的n个数据与标签值进行计算相关系数和均方根误差,如下图所示。并计算得分。
赛题理解
Nino3.4(西经 170°–120°,南北纬 5°以内区域中的平均 SST 值)就是本次赛题的标签。
训练数据对应的标签数据是当前时刻Nino3.4 SST(170°–120°W,5°S–5°N)异常指数的三个月滑动平均值。三个月滑动平均值为当前月与未来两个月的平均值。红框内的区域SST(解释:计算出来当月的SST均值后,还需要计算未来两个月的SST均值,然后求平均才是本月的nino3.4指标)
根据赛题本意,每一个月,在世界地图上(东经 0°–360°,南纬 55°到北纬 60°),标注了海平面温度(SST)、热含量异常(T300)、纬向风异常(Ua)、经向风异常(Va)数据,地图可以看做是一个4* 24* 72的图片(4个通道数代表SST/T300/UA/VA参数)。一个月对应了一张图片,而且每一张图片都能对应一个Nino3.4指数。
参考EDA
具体来说,需要根据一年(12个月)的气候变化(sst/t300/ua/va),推断出未来2年(24个月)的nino3.4指标。
思路一:根据12张图片(4 * 24 * 72)推断未来24张图片(4 * 24 * 72),再根据推断的图片,计算得到每个月的nino3.4指标(流程1)。
思路二:根据12张图片(4 * 24 * 72)直接预测未来2年(24个月)的nino3.4指标(流程2)。
数据探索
验证nino3.4标签
每一个月的nino3.4指标是根据每一个月的SST指数计算得来的吗(西经 170°–120°,南北纬 5°以内区域中的平均 SST 值,滑动三个月)?验证nino3.4指标是否是由此得来的。
- 提取西经 170°–120°,南北纬 5°以内区域中 SST 值,计算其与标签的关系。
- 根据测试结果,前24个月的SST指数均值滑动3个月,能够对应上nino3.4指标,但是之后的就对应不上了,但是总体相关系数达到0.991,平均绝对误差为0.087 左右,很奇怪,通过验证数据,没有发现问题所在。
- 对CMIP_train数据做同样测试,用SST指数均值滑动3个月,能够对应上nino3.4指标,相关系数以及平均绝对误差都可以对应。是否SODA数据存在问题?CMIP5和CMIP6都经过测试。
- SODA 数据只有前24个月的数据符合nino3.4指标的构建规则,后面100年的数据趋势符合,但是不能完全重合
- CMIP 数据符合nino3.4指标的构建规则
结论
根据官方解释:
准确的label是根据标准1* 1的海温甚至更高精度的海温计算的,而本次比赛5* 5精度的海温计算的肯定有误差。
SODA前24个月的数据一致是因为前24个月没有1* 1的观测数据,只能用这个5* 5计算出来的代替,所以一致。
CMIP数据没有真实样本资料,而SODA观测是有真实样本的。所以SODA的label是更准确的。
数据是没有问题的
缺失值删除
样本个数大致可以看成:
CMIP5+CMIP6+SODA = 2265 + 2380 +100 = 4745
含有缺失值的样本个数有 775个
EDA中虽然说缺失值大多是陆地,但是还是将其删除了
模型构建
思路
-
模型构建参考了Baseline ,主要思路是利用CNN+LSTM来构建,B榜最高的一次分数是26分。
-
经纬度外加4个特征,可以看作图片的长、宽和通道(4,24,72)
-
B榜分两次进行训练
-
第一次是CMIP数据划分8:2 进行训练 将含有空值的样本去除了
-
利用训练好的模型,在SODA数据上微调,SODA数据划分 8:2
模型
class simpleSpatailTimeNN(nn.Module):
def __init__(self, n_cnn_layer:int=1, kernals:list=[3], n_lstm_units:int=64):
super(simpleSpatailTimeNN, self).__init__()
self.conv1 = nn.Conv2d(4,4,3,padding = 1)
self.batch_norm = nn.BatchNorm1d(12, affine=False)
self.lstm = nn.LSTM(24*72*4, n_lstm_units, 2, bidirectional=True,batch_first=True)
self.pool3 = nn.AdaptiveAvgPool2d((1, 128))
self.linear = nn.Linear(128, 24)
def forward(self, sst, t300, ua, va):
Seqs = []
for i in range(12):
sst_tmp = sst[:,i,:,:].unsqueeze(1) #[batch,1,24,72]
t300_tmp = t300[:,i,:,:].unsqueeze(1)
ua_tmp = ua[:,i,:,:].unsqueeze(1)
va_tmp = va[:,i,:,:].unsqueeze(1)
seq1 = torch.cat([sst_tmp,t300_tmp,ua_tmp,va_tmp],dim=1) #[batch,4,24,72]
seq1 = self.conv1(seq1)#[batch,4,24,72]
seq1 = torch.flatten(seq1, start_dim=1).unsqueeze(1)#[batch,4*24*72]
Seqs.append(seq1)# [batch,1,4*24*72] * 12
x = torch.cat([Seqs[i] for i in range(12)], dim=1) #[batch,12,4*24*72]
x = self.batch_norm(x)
x, _ = self.lstm(x)
x = self.pool3(x).squeeze(dim=-2)
x = self.linear(x)
return x
几次提交记录
其他尝试
- 使用SST训练
- 使用SST+T300训练
- 提取前12个月的nino3.4指数,使用全连接层直接训练
- 使用Resnet18模型直接输出,线上-1.3573分
- 使用ConvLstm模型,废了很大劲修改模型,线上22.7分
- 使用6个月数据进行训练,1-6、2-7… 7-12分别进行训练,相当于构建了7个模型进行融合线上10分
- 使用滑窗构建数据(测试集开始月份是随机的,并不是都从1月份开始),一共可以构建接近5W个样本,进行训练,效果很差。
- 因为数据验证波动很大,所以在验证集如何构建上变化了很多次,最终选择了SODA再训练验证方式。
Docker常用操作
- 进入镜像仓库https://cr.console.aliyun.com ,创建一个命名空间、创建一个镜像(复制镜像地址)
- 在本机安装docker,安装完成后,使用命令行登录阿里云的仓库,输入密码
#登录
docker login --username=xxx registry.cn-hangzhou.aliyuncs.com
#在本地构建镜像 本地Dockerfile文件构建
#镜像地址registry.cn-hangzhou.aliyuncs.com/littlesix/ai_earth_submit
docker build -t registry.cn-hangzhou.aliyuncs.com/littlesix/ai_earth_submit:1.0 .
#开启一个bash命令行,运行本地镜像
docker run -it registry.cn-hangzhou.aliyuncs.com/littlesix/ai_earth_submit:1.0 bash
docker run -it registry.cn-hangzhou.aliyuncs.com/littlesix/ai_earth_submit:1.0 sh run.sh
#推送镜像到云端
docker push registry.cn-hangzhou.aliyuncs.com/littlesix/ai_earth_submit:1.0
#挂在数据目录 -v 本地目录:镜像地址 当前目录用/ 绝对目录用\
docker run -it -v /tcdata/enso_round1_test_20210201/:/tcdata/enso_round1_test_20210201/ registry.cn-hangzhou.aliyuncs.com/littlesix/ai_earth_submit:4.0 sh run.sh
docker run -it -v D:\jupyter\WeatherOceanForecasts\tcdata\enso_round1_test_20210201\:/tcdata/enso_round1_test_20210201/ registry.cn-hangzhou.aliyuncs.com/littlesix/ai_submit_pytorch:1.0 sh run.sh
docker run -it -v D:\jupyter\WeatherOceanForecasts\tcdata\enso_round1_test_20210201\:/tcdata/enso_round1_test_20210201/ registry.cn-hangzhou.aliyuncs.com/littlesix/ai_submit_pytorch:1.0 bash
#提交容器 形成新镜像
docker commit contain_id registry.cn-hangzhou.aliyuncs.com/littlesix/ai_earth_submit:6.0
#在容器内删除tcdata文件夹
rm tcdata -r
#向容器中添加文件
docker cp C:\Users\Administrator\Desktop\wheather\mlp_predict.py contain_id:./
docker cp D:\jupyter\WeatherOceanForecasts\user_data\ref.pt contain_id:./user_data
总结:
- 前期一定一定要确定自己的baseline以及线下验证方式。如果有相关比赛SOTA(state-of-the-art),或者baseline,会节省很多时间。
- 每次提交就是一次实验,实验记录一定要记清楚,所使用的方法,特征,模型等,形成一个单独的版本,方便复盘与思考。
通过这次比赛:
- 学习了pytorch的常用操作。数据集构建、模型构建、训练、测试等。
- 学习了RNN/LSTM的使用方式。
- 学习了pytorch中已有模型的修改方式,如Resnet18等。
- 学习了ConvLstm的使用方式,只能跑通,但是对使用效果、修改模型等还需要进一步了解。
- 巩固和学习了docker的使用。