写点什么

人工智能创新挑战赛:海洋气象预测 Baseline[4] 完整版(TensorFlow、torch 版本)含数据转化、模型构建、MLP、TCNN+RNN、LSTM 模型训练以及预测

  • 2023-06-07
    浙江
  • 本文字数:11938 字

    阅读完需:约 39 分钟

人工智能创新挑战赛:海洋气象预测Baseline[4]完整版(TensorFlow、torch版本)含数据转化、模型构建、MLP、TCNN+RNN、LSTM模型训练以及预测

人工智能创新挑战赛:海洋气象预测 Baseline[4]完整版(TensorFlow、torch 版本)含数据转化、模型构建、MLP、TCNN+RNN、LSTM 模型训练以及预测

1.赛题简介

项目链接以及码源见文末

2021 “AI Earth” 人工智能创新挑战赛,以 “AI 助力精准气象和海洋预测” 为主题,旨在探索人工智能技术在气象和海洋领域的应用。


本赛题的背景是厄尔尼诺 - 南方涛动(ENSO)现象。ENSO 现象是厄尔尼诺(EN)现象和南方涛动(SO)现象的合称,其中厄尔尼诺现象是指赤道中东太平洋附近的海表面温度持续异常增暖的现象,南方涛动现象是指热带东太平洋与热带西太平洋气压场存在的气压变化相反的跷跷板现象。厄尔尼诺现象和南方涛动现象实际是反常气候分别在海洋和大气中的表现,二者密切相关,因此合称为厄尔尼诺 - 南方涛动现象。


ENSO 现象会在世界大部分地区引起极端天气,对全球的天气、气候以及粮食产量具有重要的影响,准确预测 ENSO,是提高东亚和全球气候预测水平和防灾减灾的关键。Nino3.4 指数是 ENSO 现象监测的一个重要指标,它是指 Nino3.4 区(170°W - 120°W,5°S - 5°N)的平均海温距平指数,用于反应海表温度异常,若 Nino3.4 指数连续 5 个月超过 0.5℃就判定为一次 ENSO 事件。本赛题的目标,就是基于历史气候观测和模式模拟数据,利用 T 时刻过去 12 个月(包含 T 时刻)的时空序列,预测未来 1 - 24 个月的 Nino3.4 指数。





基于以上信息可以看出,我们本期的组队学习要完成的是一个时空序列的预测任务。

竞赛题目

数据简介

本赛题使用的训练数据包括 CMIP5 中 17 个模式提供的 140 年的历史模拟数据、CMIP6 中 15 个模式提供的 151 年的历史模拟数据和美国 SODA 模式重建的 100 年的历史观测同化数据,采用 nc 格式保存,其中 CMIP5 和 CMIP6 分别是世界气候研究计划(WCRP)的第 5 次和第 6 次耦合模式比较计划,这二者都提供了多种不同的气候模式对于多种气候变量的模拟数据。这些数据包含四种气候变量:海表温度异常(SST)、热含量异常(T300)、纬向风异常(Ua)、经向风异常(Va),数据维度为(year, month, lat, lon),对于训练数据提供对应月份的 Nino3.4 指数标签数据。简而言之,提供的训练数据中的每个样本为某年、某月、某个维度、某个经度的 SST、T300、Ua、Va 数值,标签为对应年、对应月的 Nino3.4 指数。


需要注意的是,样本的第二维度 month 的长度不是 12 个月,而是 36 个月,对应从当前 year 开始连续三年的数据,例如 SODA 训练数据中 year 为 0 时包含的是从第 1 - 第 3 年逐月的历史观测数据,year 为 1 时包含的是从第 2 年 - 第 4 年逐月的历史观测数据,也就是说,样本在时间上是有交叉的。



另外一点需要注意的是,Nino3.4 指数是 Nino3.4 区域从当前月开始连续三个月的 SST 平均值,也就是说,我们也可以不直接预测 Nino3.4 指数,而是以 SST 为预测目标,间接求得 Nino3.4 指数。


测试数据为国际多个海洋资料同化结果提供的随机抽取的段长度为 12 个月的时间序列,数据采用 npy 格式保存,维度为(12, lat, lon, 4),第一维度为连续的 12 个月份,第四维度为 4 个气候变量,按 SST、T300、Ua、Va 的顺序存放。测试集文件序列的命名如 test_00001_01_12.npy 中 00001 表示编号,01 表示起始月份,12 表示终止月份。

训练数据说明

每个数据样本第一维度(year)表征数据所对应起始年份,对于 CMIP 数据共 4645 年,其中 1-2265 为 CMIP6 中 15 个模式提供的 151 年的历史模拟数据(总共:151 年 *15 个模式=2265);2266-4645 为 CMIP5 中 17 个模式提供的 140 年的历史模拟数据(总共:140 年 *17 个模式=2380)。对于历史观测同化数据为美国提供的 SODA 数据。


其中每个样本第二维度(mouth)表征数据对应的月份,对于训练数据均为 36,对应的从当前年份开始连续三年数据(从 1 月开始,共 36 月),比如:


SODA_train.nc 中[0,0:36,:,:]为第 1-第 3 年逐月的历史观测数据;


SODA_train.nc 中[1,0:36,:,:]为第 2-第 4 年逐月的历史观测数据;


…,


SODA_train.nc 中[99,0:36,:,:]为第 100-102 年逐月的历史观测数据。



CMIP_train.nc 中[0,0:36,:,:]为 CMIP6 第一个模式提供的第 1-第 3 年逐月的历史模拟数据;


…,


CMIP_train.nc 中[150,0:36,:,:]为 CMIP6 第一个模式提供的第 151-第 153 年逐月的历史模拟数据;


CMIP_train.nc 中[151,0:36,:,:]为 CMIP6 第二个模式提供的第 1-第 3 年逐月的历史模拟数据;


…,


CMIP_train.nc 中[2265,0:36,:,:]为 CMIP5 第一个模式提供的第 1-第 3 年逐月的历史模拟数据;


…,


CMIP_train.nc 中[2405,0:36,:,:]为 CMIP5 第二个模式提供的第 1-第 3 年逐月的历史模拟数据;


…,


CMIP_train.nc 中[4644,0:36,:,:]为 CMIP5 第 17 个模式提供的第 140-第 142 年逐月的历史模拟数据。


其中每个样本第三、第四维度分别代表经纬度(南纬 55 度北纬 60 度,东经 0360 度),所有数据的经纬度范围相同。

训练数据标签说明

标签数据为 Nino3.4 SST 异常指数,数据维度为(year,month)。


CMIP(SODA)_train.nc 对应的标签数据当前时刻 Nino3.4 SST 异常指数的三个月滑动平均值,因此数据维度与维度介绍同训练数据一致


注:三个月滑动平均值为当前月与未来两个月的平均值。

测试数据说明

测试用的初始场(输入)数据为国际多个海洋资料同化结果提供的随机抽取的 n 段 12 个时间序列,数据格式采用 NPY 格式保存,维度为(12,lat,lon, 4),12 为 t 时刻及过去 11 个时刻,4 为预测因子,并按照 SST,T300,Ua,Va 的顺序存放。


测试集文件序列的命名规则:test_编号_起始月份_终止月份.npy,如 test_00001_01_12_.npy。

评估指标

本赛题的评估指标如下:



其中为相关性技巧评分,计算方式如下:



可以看出,月份增加时系数也增大,也就是说,模型能准确预测的时间越长,评分就越高。


是对于个测试集样本在时刻的预测值与实际值的相关系数,计算公式如下:


$$&br;cor_i = \frac{\sum_{j=1}^N(y_{truej}-\bar{y}{true})(y{predj}-\bar{y}{pred})}{\sqrt{\sum(y{truej}-\bar{y}{true})^2\sum(y{predj}-\bar{y}{pred})^2}}&br;$$其中 $y{truej}ij\bar{y}{true}Ny{predj}ij\bar{y}_{pred}N$个测试集样本的预测 Nino3.4 指数的均值。


为 24 个月份的累计均方根误差,计算公式为:



赛题分析

分析上述赛题信息可以发现,我们需要解决的是以下问题:


  • 对于一个时空序列预测问题,要如何挖掘时间信息?如何挖掘空间信息?

  • 数据中给出的特征是四个气象领域公认的、通用的气候变量,我们很难再由此构造新的特征。如果不构造新的特征,要如何从给出的特征中挖掘出更多的信息?

  • 训练集的数据量不大,总共只有个训练样本,对于数据量小的预测问题,我们通常需要从以下两方面考虑:

  • 如何增加数据量?

  • 如何构造小(参数量小,减小过拟合风险)而深(能提取出足够丰富的信息)的模型?

2.线下数据转换

  • 将数据转化为我们所熟悉的形式,每个人的风格不一样,此处可以作为如何将 nc 文件转化为 csv 等文件

数据转化

## 工具包导入&数据读取### 工具包导入
'''安装工具# !pip install netCDF4 ''' import pandas as pdimport numpy as npimport tensorflow as tffrom tensorflow.keras.optimizers import Adamimport matplotlib.pyplot as pltimport scipy from netCDF4 import Datasetimport netCDF4 as ncimport gc%matplotlib inline
复制代码

数据读取

SODA_label 处理

  1. 标签含义


标签数据为Nino3.4 SST异常指数,数据维度为(year,month)。  CMIP(SODA)_train.nc对应的标签数据当前时刻Nino3.4 SST异常指数的三个月滑动平均值,因此数据维度与维度介绍同训练数据一致注:三个月滑动平均值为当前月与未来两个月的平均值。
复制代码


  1. 将标签转化为我们熟悉的 pandas 形式


label_path       = './data/SODA_label.nc'label_trans_path = './data/' nc_label         = Dataset(label_path,'r') years            = np.array(nc_label['year'][:])months           = np.array(nc_label['month'][:])
year_month_index = []vs = []for i,year in enumerate(years): for j,month in enumerate(months): year_month_index.append('year_{}_month_{}'.format(year,month)) vs.append(np.array(nc_label['nino'][i,j]))
df_SODA_label = pd.DataFrame({'year_month':year_month_index}) df_SODA_label['year_month'] = year_month_indexdf_SODA_label['label'] = vs
df_SODA_label.to_csv(label_trans_path + 'df_SODA_label.csv',index = None)
复制代码


df_SODA_label.head()
复制代码


<div><style scoped>.dataframe tbody tr th:only-of-type {vertical-align: middle;}


.dataframe tbody tr th {    vertical-align: top;}
.dataframe thead th { text-align: right;}
复制代码


</style><table border="1" class="dataframe"><thead><tr style="text-align: right;"><th></th><th>year_month</th><th>label</th></tr></thead><tbody><tr><th>0</th><td>year_1_month_1</td><td>-0.40720701217651367</td></tr><tr><th>1</th><td>year_1_month_2</td><td>-0.20244435966014862</td></tr><tr><th>2</th><td>year_1_month_3</td><td>-0.10386104136705399</td></tr><tr><th>3</th><td>year_1_month_4</td><td>-0.02910841442644596</td></tr><tr><th>4</th><td>year_1_month_5</td><td>-0.13252995908260345</td></tr></tbody></table></div>

转化

SODA_train 处理

SODA_train.nc中[0,0:36,:,:]为第1-第3年逐月的历史观测数据;
SODA_train.nc中[1,0:36,:,:]为第2-第4年逐月的历史观测数据;…,SODA_train.nc中[99,0:36,:,:]为第100-102年逐月的历史观测数据。
复制代码


SODA_path        = './data/SODA_train.nc'nc_SODA          = Dataset(SODA_path,'r') 
复制代码


  • 自定义抽取对应数据 &转化为 df 的形式;


index 为年月; columns 为 lat 和 lon 的组合


def trans_df(df, vals, lats, lons, years, months):    '''        (100, 36, 24, 72) -- year, month,lat,lon     '''     for j,lat_ in enumerate(lats):        for i,lon_ in enumerate(lons):            c = 'lat_lon_{}_{}'.format(int(lat_),int(lon_))              v = []            for y in range(len(years)):                for m in range(len(months)):                     v.append(vals[y,m,j,i])            df[c] = v    return df
复制代码


year_month_index = []
years = np.array(nc_SODA['year'][:])months = np.array(nc_SODA['month'][:])lats = np.array(nc_SODA['lat'][:])lons = np.array(nc_SODA['lon'][:])

for year in years: for month in months: year_month_index.append('year_{}_month_{}'.format(year,month))
df_sst = pd.DataFrame({'year_month':year_month_index}) df_t300 = pd.DataFrame({'year_month':year_month_index}) df_ua = pd.DataFrame({'year_month':year_month_index}) df_va = pd.DataFrame({'year_month':year_month_index})
复制代码


%%timedf_sst = trans_df(df = df_sst, vals = np.array(nc_SODA['sst'][:]), lats = lats, lons = lons, years = years, months = months)df_t300 = trans_df(df = df_t300, vals = np.array(nc_SODA['t300'][:]), lats = lats, lons = lons, years = years, months = months)df_ua   = trans_df(df = df_ua, vals = np.array(nc_SODA['ua'][:]), lats = lats, lons = lons, years = years, months = months)df_va   = trans_df(df = df_va, vals = np.array(nc_SODA['va'][:]), lats = lats, lons = lons, years = years, months = months)
复制代码


label_trans_path = './data/'df_sst.to_csv(label_trans_path  + 'df_sst_SODA.csv',index = None)df_t300.to_csv(label_trans_path + 'df_t300_SODA.csv',index = None)df_ua.to_csv(label_trans_path   + 'df_ua_SODA.csv',index = None)df_va.to_csv(label_trans_path   + 'df_va_SODA.csv',index = None)
复制代码

CMIP_label 处理

label_path       = './data/CMIP_label.nc'label_trans_path = './data/'nc_label         = Dataset(label_path,'r') years            = np.array(nc_label['year'][:])months           = np.array(nc_label['month'][:])
year_month_index = []vs = []for i,year in enumerate(years): for j,month in enumerate(months): year_month_index.append('year_{}_month_{}'.format(year,month)) vs.append(np.array(nc_label['nino'][i,j]))
df_CMIP_label = pd.DataFrame({'year_month':year_month_index}) df_CMIP_label['year_month'] = year_month_indexdf_CMIP_label['label'] = vs
df_CMIP_label.to_csv(label_trans_path + 'df_CMIP_label.csv',index = None)
复制代码


df_CMIP_label.head()
复制代码


<div><style scoped>.dataframe tbody tr th:only-of-type {vertical-align: middle;}


.dataframe tbody tr th {    vertical-align: top;}
.dataframe thead th { text-align: right;}
复制代码


</style><table border="1" class="dataframe"><thead><tr style="text-align: right;"><th></th><th>year_month</th><th>label</th></tr></thead><tbody><tr><th>0</th><td>year_1_month_1</td><td>-0.26102548837661743</td></tr><tr><th>1</th><td>year_1_month_2</td><td>-0.1332537680864334</td></tr><tr><th>2</th><td>year_1_month_3</td><td>-0.014831557869911194</td></tr><tr><th>3</th><td>year_1_month_4</td><td>0.10506672412157059</td></tr><tr><th>4</th><td>year_1_month_5</td><td>0.24070978164672852</td></tr></tbody></table></div>

CMIP_train 处理


CMIP_train.nc中[0,0:36,:,:]为CMIP6第一个模式提供的第1-第3年逐月的历史模拟数据;…,CMIP_train.nc中[150,0:36,:,:]为CMIP6第一个模式提供的第151-第153年逐月的历史模拟数据;
CMIP_train.nc中[151,0:36,:,:]为CMIP6第二个模式提供的第1-第3年逐月的历史模拟数据;…,CMIP_train.nc中[2265,0:36,:,:]为CMIP5第一个模式提供的第1-第3年逐月的历史模拟数据;…,CMIP_train.nc中[2405,0:36,:,:]为CMIP5第二个模式提供的第1-第3年逐月的历史模拟数据;…,CMIP_train.nc中[4644,0:36,:,:]为CMIP5第17个模式提供的第140-第142年逐月的历史模拟数据。
其中每个样本第三、第四维度分别代表经纬度(南纬55度北纬60度,东经0360度),所有数据的经纬度范围相同。
复制代码


CMIP_path       = './data/CMIP_train.nc'CMIP_trans_path = './data'nc_CMIP  = Dataset(CMIP_path,'r') 
复制代码


nc_CMIP.variables.keys()
复制代码


dict_keys(['sst', 't300', 'ua', 'va', 'year', 'month', 'lat', 'lon'])
复制代码


nc_CMIP['t300'][:].shape
复制代码


(4645, 36, 24, 72)
复制代码


year_month_index = []
years = np.array(nc_CMIP['year'][:])months = np.array(nc_CMIP['month'][:])lats = np.array(nc_CMIP['lat'][:])lons = np.array(nc_CMIP['lon'][:])
last_thre_years = 1000for year in years: ''' 数据的原因,我们 ''' if year >= 4645 - last_thre_years: for month in months: year_month_index.append('year_{}_month_{}'.format(year,month))
df_CMIP_sst = pd.DataFrame({'year_month':year_month_index}) df_CMIP_t300 = pd.DataFrame({'year_month':year_month_index}) df_CMIP_ua = pd.DataFrame({'year_month':year_month_index}) df_CMIP_va = pd.DataFrame({'year_month':year_month_index})
复制代码


  • 因为内存限制,我们暂时取最后 1000 个 year 的数据


def trans_thre_df(df, vals, lats, lons, years, months, last_thre_years = 1000):    '''        (4645, 36, 24, 72) -- year, month,lat,lon     '''     for j,lat_ in (enumerate(lats)):#         print(j)        for i,lon_ in enumerate(lons):            c = 'lat_lon_{}_{}'.format(int(lat_),int(lon_))              v = []            for y_,y in enumerate(years):                '''                    数据的原因,我们                '''                if y >= 4645 - last_thre_years:                    for m_,m in  enumerate(months):                         v.append(vals[y_,m_,j,i])            df[c] = v    return df
复制代码


%%timedf_CMIP_sst  = trans_thre_df(df = df_CMIP_sst,  vals   = np.array(nc_CMIP['sst'][:]),  lats = lats, lons = lons, years = years, months = months)df_CMIP_sst.to_csv(CMIP_trans_path + 'df_CMIP_sst.csv',index = None)del df_CMIP_sstgc.collect()
df_CMIP_t300 = trans_thre_df(df = df_CMIP_t300, vals = np.array(nc_CMIP['t300'][:]), lats = lats, lons = lons, years = years, months = months)df_CMIP_t300.to_csv(CMIP_trans_path + 'df_CMIP_t300.csv',index = None)del df_CMIP_t300gc.collect()
df_CMIP_ua = trans_thre_df(df = df_CMIP_ua, vals = np.array(nc_CMIP['ua'][:]), lats = lats, lons = lons, years = years, months = months)df_CMIP_ua.to_csv(CMIP_trans_path + 'df_CMIP_ua.csv',index = None)del df_CMIP_uagc.collect()
df_CMIP_va = trans_thre_df(df = df_CMIP_va, vals = np.array(nc_CMIP['va'][:]), lats = lats, lons = lons, years = years, months = months)df_CMIP_va.to_csv(CMIP_trans_path + 'df_CMIP_va.csv',index = None)del df_CMIP_vagc.collect()
复制代码


(36036, 1729)
复制代码

3.数据建模

工具包导入 &数据读取

工具包导入

import pandas as pdimport numpy  as npimport tensorflow as tffrom tensorflow.keras.optimizers import Adam import joblibfrom netCDF4 import Datasetimport netCDF4 as ncimport gcfrom   sklearn.metrics import mean_squared_errorimport numpy as npfrom tensorflow.keras.callbacks import LearningRateScheduler, Callbackimport tensorflow.keras.backend as Kfrom tensorflow.keras.layers import *from tensorflow.keras.models import *from tensorflow.keras.optimizers import *from tensorflow.keras.callbacks import *from tensorflow.keras.layers import Input %matplotlib inline 
复制代码

数据读取

SODA_label 处理

  1. 标签含义


标签数据为Nino3.4 SST异常指数,数据维度为(year,month)。  CMIP(SODA)_train.nc对应的标签数据当前时刻Nino3.4 SST异常指数的三个月滑动平均值,因此数据维度与维度介绍同训练数据一致注:三个月滑动平均值为当前月与未来两个月的平均值。
复制代码


  1. 将标签转化为我们熟悉的 pandas 形式


df_SODA_label = pd.read_csv('./data/df_SODA_label.csv')df_CMIP_label = pd.read_csv('./data/df_CMIP_label.csv') 
复制代码

训练集验证集构建

df_SODA_label['year']  = df_SODA_label['year_month'].apply(lambda x: x[:x.find('m') - 1])df_SODA_label['month'] = df_SODA_label['year_month'].apply(lambda x: x[x.find('m') :])
df_train = pd.pivot_table(data = df_SODA_label, values = 'label',index = 'year', columns = 'month')year_new_index = ['year_{}'.format(i+1) for i in range(df_train.shape[0])]month_new_columns = ['month_{}'.format(i+1) for i in range(df_train.shape[1])]df_train = df_train[month_new_columns].loc[year_new_index]
复制代码

模型构建

MLP 框架

def RMSE(y_true, y_pred):    return tf.sqrt(tf.reduce_mean(tf.square(y_true - y_pred)))
def RMSE_fn(y_true, y_pred): return np.sqrt(np.mean(np.power(np.array(y_true, float).reshape(-1, 1) - np.array(y_pred, float).reshape(-1, 1), 2)))
def build_model(train_feat, test_feat): #allfeatures, inp = Input(shape=(len(train_feat))) x = Dense(1024, activation='relu')(inp) x = Dropout(0.25)(x) x = Dense(512, activation='relu')(x) x = Dropout(0.25)(x) output = Dense(len(test_feat), activation='linear')(x) model = Model(inputs=inp, outputs=output)
adam = tf.optimizers.Adam(lr=1e-3,beta_1=0.99,beta_2 = 0.99) model.compile(optimizer=adam, loss=RMSE)
return model
复制代码

模型训练

feature_cols = ['month_{}'.format(i+1) for i in range(12)]label_cols   = ['month_{}'.format(i+1) for i in range(12, df_train.shape[1])] 
复制代码


model_mlp = build_model(feature_cols, label_cols)model_mlp.summary()
复制代码


Model: "model"_________________________________________________________________Layer (type)                 Output Shape              Param #   =================================================================input_1 (InputLayer)         [(None, 12)]              0         _________________________________________________________________dense (Dense)                (None, 1024)              13312     _________________________________________________________________dropout (Dropout)            (None, 1024)              0         _________________________________________________________________dense_1 (Dense)              (None, 512)               524800    _________________________________________________________________dropout_1 (Dropout)          (None, 512)               0         _________________________________________________________________dense_2 (Dense)              (None, 24)                12312     =================================================================Total params: 550,424Trainable params: 550,424Non-trainable params: 0_________________________________________________________________
复制代码


tr_len = int(df_train.shape[0] * 0.8)tr_fea     = df_train[feature_cols].iloc[:tr_len,:].copy()tr_label   = df_train[label_cols].iloc[:tr_len,:].copy() val_fea     = df_train[feature_cols].iloc[tr_len:,:].copy()val_label   = df_train[label_cols].iloc[tr_len:,:].copy() 

model_weights = './user_data/model_data/model_mlp_baseline.h5'
checkpoint = ModelCheckpoint(model_weights, monitor='val_loss', verbose=0, save_best_only=True, mode='min', save_weights_only=True)
plateau = ReduceLROnPlateau(monitor='val_loss', factor=0.5, patience=5, verbose=1, min_delta=1e-4, mode='min')early_stopping = EarlyStopping(monitor="val_loss", patience=20)history = model_mlp.fit(tr_fea.values, tr_label.values, validation_data=(val_fea.values, val_label.values), batch_size=4096, epochs=200, callbacks=[plateau, checkpoint, early_stopping], verbose=2)
复制代码


Epoch 00053: ReduceLROnPlateau reducing learning rate to 6.25000029685907e-05.1/1 - 0s - loss: 0.6567 - val_loss: 0.6030Epoch 54/2001/1 - 0s - loss: 0.6571 - val_loss: 0.6030Epoch 55/2001/1 - 0s - loss: 0.6541 - val_loss: 0.6030Epoch 56/2001/1 - 0s - loss: 0.6539 - val_loss: 0.6030Epoch 57/2001/1 - 0s - loss: 0.6477 - val_loss: 0.6030Epoch 58/200
Epoch 00058: ReduceLROnPlateau reducing learning rate to 3.125000148429535e-05.1/1 - 0s - loss: 0.6498 - val_loss: 0.6029Epoch 59/2001/1 - 0s - loss: 0.6451 - val_loss: 0.6029Epoch 60/2001/1 - 0s - loss: 0.6458 - val_loss: 0.6029
复制代码

Metrics

def rmse(y_true, y_preds):    return np.sqrt(mean_squared_error(y_pred = y_preds, y_true = y_true))
def score(y_true, y_preds): accskill_score = 0 rmse_score = 0 a = [1.5] * 4 + [2] * 7 + [3] * 7 + [4] * 6 y_true_mean = np.mean(y_true,axis=0) y_pred_mean = np.mean(y_true,axis=0)
for i in range(24): fenzi = np.sum((y_true[:,i] - y_true_mean[i]) *(y_preds[:,i] - y_pred_mean[i]) ) fenmu = np.sqrt(np.sum((y_true[:,i] - y_true_mean[i])**2) * np.sum((y_preds[:,i] - y_pred_mean[i])**2) ) cor_i= fenzi / fenmu accskill_score += a[i] * np.log(i+1) * cor_i rmse_score += rmse(y_true[:,i], y_preds[:,i]) return 2 / 3.0 * accskill_score - rmse_score
复制代码


y_val_preds = model_mlp.predict(val_fea.values, batch_size=1024)print('score', score(y_true = val_label.values, y_preds = y_val_preds))
复制代码

4.模型预测

模型构建

在上面的部分,我们已经训练好了模型,接下来就是提交模型并在线上进行预测,这块可以分为三步:


  • 导入模型;

  • 读取测试数据并且进行预测;

  • 生成提交所需的版本;


import tensorflow as tfimport tensorflow.keras.backend as Kfrom tensorflow.keras.layers import *from tensorflow.keras.models import *from tensorflow.keras.optimizers import *from tensorflow.keras.callbacks import *from tensorflow.keras.layers import Input import numpy as npimport osimport zipfile
def RMSE(y_true, y_pred): return tf.sqrt(tf.reduce_mean(tf.square(y_true - y_pred)))
def build_model(train_feat, test_feat): #allfeatures, inp = Input(shape=(len(train_feat))) x = Dense(1024, activation='relu')(inp) x = Dropout(0.25)(x) x = Dense(512, activation='relu')(x) x = Dropout(0.25)(x) output = Dense(len(test_feat), activation='linear')(x) model = Model(inputs=inp, outputs=output)
adam = tf.optimizers.Adam(lr=1e-3,beta_1=0.99,beta_2 = 0.99) model.compile(optimizer=adam, loss=RMSE)
return model
feature_cols = ['month_{}'.format(i+1) for i in range(12)]label_cols = ['month_{}'.format(i+1) for i in range(12, 36)] model = build_model(train_feat=feature_cols, test_feat=label_cols)model.load_weights('./user_data/model_data/model_mlp_baseline.h5')
复制代码

模型预测


test_path = './tcdata/enso_round1_test_20210201/'
### 0. 模拟线上的测试集合# for i in range(10):# x = np.random.random(12) # np.save(test_path + "{}.npy".format(i+1),x)
### 1. 测试数据读取files = os.listdir(test_path)test_feas_dict = {}for file in files: test_feas_dict[file] = np.load(test_path + file) ### 2. 结果预测test_predicts_dict = {}for file_name,val in test_feas_dict.items(): test_predicts_dict[file_name] = model.predict(val.reshape([-1,12]))# test_predicts_dict[file_name] = model.predict(val.reshape([-1,12])[0,:])
### 3.存储预测结果for file_name,val in test_predicts_dict.items(): np.save('./result/' + file_name,val)
复制代码

打包到 run.sh 目录下方

#打包目录为zip文件def make_zip(source_dir='./result/', output_filename = 'result.zip'):    zipf = zipfile.ZipFile(output_filename, 'w')    pre_len = len(os.path.dirname(source_dir))    source_dirs = os.walk(source_dir)    print(source_dirs)    for parent, dirnames, filenames in source_dirs:        print(parent, dirnames)        for filename in filenames:            if '.npy' not in filename:                continue            pathfile = os.path.join(parent, filename)            arcname = pathfile[pre_len:].strip(os.path.sep)   #相对路径            zipf.write(pathfile, arcname)    zipf.close()make_zip() 
复制代码

项目链接以及码源

云端链接:人工智能创新挑战赛海洋气象预测Baseline[4]完整版


更多文章请关注公重号:汀丶人工智能


5.提升方向

模型性能提升可以参考:在下述基础上改动


“AI Earth”人工智能创新挑战赛:助力精准气象和海洋预测Baseline[2]:数据探索性分析(温度风场可视化)、CNN+LSTM模型建模


“AI Earth”人工智能创新挑战赛:助力精准气象和海洋预测Baseline[3]:TCNN+RNN模型、SA-ConvLSTM模型


  • 模型角度:我们只使用了简单的 MLP 模型进行建模,可以考虑使用其它的更加 fancy 的模型进行尝试;

  • 数据层面:构建一些特征或者对数据进行一些数据变换等;

  • 针对损失函数设计各种 trick 的提升技巧;

发布于: 2023-06-07阅读数: 16
用户头像

本博客将不定期更新关于NLP等领域相关知识 2022-01-06 加入

本博客将不定期更新关于机器学习、强化学习、数据挖掘以及NLP等领域相关知识,以及分享自己学习到的知识技能,感谢大家关注!

评论

发布
暂无评论
人工智能创新挑战赛:海洋气象预测Baseline[4]完整版(TensorFlow、torch版本)含数据转化、模型构建、MLP、TCNN+RNN、LSTM模型训练以及预测_人工智能_汀丶人工智能_InfoQ写作社区