2022 社会计算创新大赛--交通量预测

2022 社会计算创新大赛 https://momodel.cn/competition
2022 社会计算创新大赛--交通量预测_第1张图片
2022 社会计算创新大赛--交通量预测_第2张图片
2022 社会计算创新大赛--交通量预测_第3张图片
任务描述:
城市是社会的重要组成,时序模型是深度学习中影响广泛的模型,该赛题目的在于加深对时序模型的理解和运用,以及对空间信息的利用。利用城市前两个小时的历史交通流量(每个交通结点每五分钟记录一次车流量)预测下一个五分钟的交通流量,数据给出了结点之间的无向图数据。

任务要求:
A、任务提供包括数据读取、基础模型、模型训练等基本代码
B、参赛选手需完成核心模型构建代码,并尽可能将模型调到最佳状态

评分方式:
评分指标为误差和的评分表映射值。

1. 赛题介绍

1.1 大赛背景

时序模型是深度学习中影响广泛的模型,该赛题目的在于加深对时序模型的理解和运用,以及对空间信息的利用。

1.2 大赛要求

利用城市前两个小时的历史交通流量(每个交通结点每五分钟记录一次车流量)预测下一个五分钟的交通流量,数据给出了结点之间的无向图数据。

1.3 大赛环境

可以使用基于 Python 的 Pandas、Numpy、Scikit-learn 等库进行相关特征处理,使用 Keras、Tensorflow、Pytorch 等框架建立深度学习模型,使用过程中请注意 Python 包(库)的版本。

1.4 评估指标

评分指标为误差和的评分表映射值。其中
误差和(error_score)=均方根误差(RMSE)+平均绝对误差(MAE)

1.5 大赛事项

使用平台的注意事项
该平台的 Notebook 在 CPU 上运行,故尽量不要尝试在 Notebook 上做希望让 GPU 做的工作。

训练模型的注意事项
如果想要线下训练模型,请保证线下的环境与该平台一致,否则可能无法在该平台运行,可以在该平台的 terminal 输入pip list查看对应包版本。

该作业的注意事项
该作业目的在于加深对空间和时序模型的理解和运用,理论上作品的预测相关指标不应低于基本模型。

1.6 参考资料

相关框架的文档
scikit-learn: https://scikit-learn.org/stable/

tensorflow: https://tensorflow.google.cn/tutorials?hl=zh_cn

pytorch: https://pytorch.org/tutorials/

该领域的论文
[NIPS2015]ConvLSTM https://papers.nips.cc/paper/5955-convolutional-lstm-network-a-machine-learning-approach-for-precipitation-nowcasting.pdf

[ICML2016]vertex domain(spatial domain) http://proceedings.mlr.press/v48/niepert16.pdf

[ICLR2018]DCRNN https://arxiv.org/pdf/1707.01926.pdf

[AAAI2019]STDN https://www.aaai.org/ojs/index.php/AAAI/article/view/4511/4389

框架的学习教程
《动手学深度学习》(Pytorch版): https://tangshusen.me/Dive-into-DL-PyTorch/

《深度学习框架PyTorch:入门与实战》: https://github.com/chenyuntc/pytorch-book

2. 赛题内容

2.1 数据集

数据集是 2018 年一月和二月的某高速公路上节选了 307 个结点的车流量统计,通过大量的传感器每五分钟统计一次。由 train_data.csv 给出。其中,行代表一个时间点,从第一行表示 2018/01/01 00:00:00-2018/01/01 00:04:59 的车流量,逐五分钟递推,给出了前 50 天的信息。列代表一个结点。某个位置上的值代表了该时间段该结点的车流量。

数据集已经经过预处理,对于缺失值以线性插值填充。

测试和评估集不在上述给出的时间范围内,是在该区域相距不远的其他时间段。

另一文件 graph.csv 给出了高速公路相互直达的结点之间的无向边和其距离。节选之后的传感器保证相距至少有 3.5 英里。

# 首先先 import 一些主要的包
import numpy as np
import pandas as pd
import time
import matplotlib.pyplot as plt

# 画图使用
%matplotlib inline
# 数据文件夹
base_path = 'datasets/60843339ef0b1353a25d0e2a-momodel/'
# 读入数据文件
data = pd.read_csv(base_path + 'train_data.csv')

# 输出数据的形状
print(data.shape)
# 输出数据的前三行
print(data.head(3))

2022 社会计算创新大赛--交通量预测_第4张图片

使用统计信息,可以看到每个结点的数量、平均值等信息。

# 输出数据的统计信息
data.describe()

2022 社会计算创新大赛--交通量预测_第5张图片

也可以对具体某几个结点绘制图像,这样可以更清晰地感受到数据。下图中可以感受到结点 5 和结点 154 的流量有明显的相似性,即使在下面的无向图中,两个结点事实上相距 347.2 英里。

# 新建一个图像
plt.figure(figsize=(16,8))

# 绘画某些结点第一天的情况(即前 288 个结点)
plt.plot(data.iloc[:288,73].values.reshape(-1),c='blue')

plt.plot(data.iloc[:288,5].values.reshape(-1),c='red')

plt.plot(data.iloc[:288,154].values.reshape(-1),c='green')

# 展示图像
plt.show()

2022 社会计算创新大赛--交通量预测_第6张图片
注意到数值较大处和较小处相比差距还是巨大的,为了深度模型更好的工作,我们使用 MinMaxScaler 进行归一化。当然,用户也可以自行选择其他的预处理方式。

这里我们选用 sklearn 的 Scaler ,如果有兴趣,也可以使用 torchvision 或者自己实现相关内容。

from sklearn.preprocessing import MinMaxScaler

scaler = MinMaxScaler(feature_range=(-1, 1))
data = np.array(data)
data_scaled = scaler.fit_transform(data.reshape(-1, 1)).reshape(data.shape)

本数据集提供了空间信息,并要求利用空间和时间信息预测未来的流量。

空间信息利用表格提供一张双向图,其中 cost 表示点与点之间的距离,单位是英里。

对于图( Graph )提取特征,目前常见的是图卷积网络( GCN ),也有一些简单的方法,比如精心挑选某些结点,抽取相邻结点构成子图,获取子图的邻接矩阵,然后利用 CNN 的方法提取特征等。

# 读入图文件
edges = pd.read_csv(base_path + 'graph.csv')

# 查看图的大小
print(edges.shape)

# 输出前十条边
print(edges.head(10))

2022 社会计算创新大赛--交通量预测_第7张图片

2.2 数据处理

首先需要生成题目所需的训练集合。

# 生成题目所需的训练集合
def generate_data(data):
    # 先将目标数据转换成 numpy 类型
    data = np.array(data)
    
    # 目标是生成可直接用于训练和测试的 x 和 y
    x = []
    y = []
    
    # 每 24 行组成一个 x , 第 25 行为需要预测的值 y
    for i in range(data.shape[0]-25):
        curr_x = data[i:i+24]
        curr_y = data[i+24:i+25]
        x.append(curr_x)
        y.append(curr_y)
        
    return x,y

然后对数据集合进行分割,其中训练集用于训练,校验集用于检验模型训练情况,测试集合用于测试模型效果。

# 生成 train valid test 集合,以供训练所需
def generate_training_data(x,y):
    # 样本总数
    num_samples = x.shape[0]
    # 测试集大小
    num_test = round(num_samples * 0.2)
    # 训练集大小
    num_train = round(num_samples * 0.7)
    # 校验集大小
    num_val = num_samples - num_test - num_train
    
    # 训练集拥有从 0 起长度为 num_train 的样本
    x_train, y_train = x[:num_train], y[:num_train]
    # 校验集拥有从 num_train 起长度为 num_val 的样本
    x_val, y_val = (
        x[num_train: num_train + num_val],
        y[num_train: num_train + num_val],
    )
    # 测试集拥有尾部 num_test 个样本
    x_test, y_test = x[-num_test:], y[-num_test:]
    
    # 返回这些集合
    return x_train, y_train, x_val, y_val, x_test, y_test

下面尝试整理空间信息,为了简化问题,我们忽略边权,用户可以自由选用,先根据表格构造出邻接矩阵。

邻接矩阵 G[a][b] 表示从 a 到 b 是否存在直接的边

# 结点个数
n_nodes = data.shape[1]
# 建立一个空的邻接矩阵
G = np.zeros(shape = (n_nodes,n_nodes))
# 输出 G 的大概外观
print(G)
# 为了方便,将 edges 转为 numpy
edges = np.array(edges,dtype=np.int32)
# 将表格中的边加入邻接矩阵
for i in range(edges.shape[0]):
    # 取一条边的两个结点
    u = edges[i][0]
    v = edges[i][1]
    # 将正向边和反向边赋值为 1
    G[u][v] = G[v][u] = 1
    
print(G)

下面研究分析一下该图的情况。

# 结点连接计数
nodes_connected_count = {}

for i in range(n_nodes):
    # 计数
    key = np.sum(G[i,:])
    
    # 如果记录过该数字,则加 1
    if key in nodes_connected_count:
        nodes_connected_count[key] += 1
    
    # 否则,则加入该元素,并赋值为 1
    else:
        nodes_connected_count[key] = 1
        
# 输出统计情况
print(nodes_connected_count)

{2.0: 194, 6.0: 3, 3.0: 29, 1.0: 50, 4.0: 20, 5.0: 10, 7.0: 1}
可以看到,该图大部分结点都仅拥有较小的度数。

2.3 建立一个简单的模型

选用一种框架,告诉其创建模型的常用方式以及常用的接口
建立一个简单模型并进行训练保存
分析模型训练过程以及模型概况
加载模型并对模型进行评估
加载模型并预测输入数据的结果

2.3.1 处理数据

该赛题示范使用 Pytorch 完成。也可以选用其他框架进行训练并预测结果。

# 加载 pytorch
import torch

# 处理数据,并将其转化为 Pytorch 的形式。
# 获取数据中的 x, y
x,y = generate_data(data_scaled)

# 将 x,y 转换乘 tensor , Pytorch 模型默认的类型是 float32
x = torch.tensor(x,dtype=torch.float32)
y = torch.tensor(y,dtype=torch.float32)

print(x.shape,y.shape)

# 将 y 的中间维度转化掉
y = y.view(y.shape[0],-1)

print(x.shape,y.shape)

torch.Size([14375, 24, 307]) torch.Size([14375, 1, 307])
torch.Size([14375, 24, 307]) torch.Size([14375, 307])

# 处理出训练集,校验集和测试集
x_train, y_train, x_val, y_val, x_test, y_test = generate_training_data(x,y)

为了方便使用 DataLoader ,我们需要自定义一个 Dataset ,自定义的 Dataset 只需要继承后实现下面三个函数。

# 建立一个自定 Dataset
class MyDataset(torch.utils.data.Dataset):
    def __init__(self, x, y):
        self.x = x
        self.y = y
 
    def __getitem__(self, item):
        return self.x[item], self.y[item]
 
    def __len__(self):
        return len(self.x)
# 建立训练数据集、校验数据集和测试数据集
train_data = MyDataset(x_train,y_train)
valid_data = MyDataset(x_val,y_val)
test_data = MyDataset(x_test,y_test)
# 规定批次的大小
batch_size = 64

# 创建对应的 DataLoader
train_iter = torch.utils.data.DataLoader(train_data, batch_size=batch_size, shuffle=True)

# 校验集和测试集的 shuffle 是没有必要的,因为每次都会全部跑一遍
valid_iter = torch.utils.data.DataLoader(valid_data, batch_size=batch_size, shuffle=False)
test_iter = torch.utils.data.DataLoader(test_data, batch_size=batch_size, shuffle=False)

2.3.2 建立模型

下面展示如何建立模型, Pytorch 的建立模型较为简单,只需要完成 forward ,即前向传播函数即可进行训练。这里展示建立一个简单的线性模型。参数 Pytorch 会自动初始化,具体请查看官方文档。

# 输入的数量是 120分钟 除以 5分钟 = 24个时间段,每个时间段有307个结点的车流量数据。
num_inputs = 120 // 5 * 307
# 输出是后 5 分钟的车流量数据
num_outputs = 307

# 建立一个简单的线性模型
class LinearNet(torch.nn.Module):
    def __init__(self, num_inputs, num_outputs):
        super(LinearNet, self).__init__()
        # 一个线性层
        self.linear = torch.nn.Linear(num_inputs, num_outputs)
        
    # 前向传播函数
    def forward(self, x): # x shape: (batch, 24, 307)
        # 这里暗含了将 x 的 shape 改变的操作
        y = self.linear(x.view(x.shape[0], -1))
        return y

下面建立一个复杂但可能不是很有效的 LSTM 模型,仅供理解 Pytorch 的运行方式而使用。

# 隐藏层的个数
num_hiddens = 128 
# 建立一个稍微复杂的 LSTM 模型
class LSTMNet(torch.nn.Module):
    def __init__(self, num_hiddens, num_outputs):
        super(LSTMNet, self).__init__()
        self.hidden_size = num_hiddens
        # RNN 层,这里的 batch_first 指定传入的是 (批大小,序列长度,序列每个位置的大小)
        # 如果不指定其为 True,传入顺序应当是 (序列长度,批大小,序列每个位置的大小)
        self.rnn = torch.nn.LSTM(input_size=num_inputs//24, hidden_size=num_hiddens,batch_first=True)
        # 线性层
        self.dense = torch.nn.Linear(self.hidden_size*24, 256)
        self.dense2 = torch.nn.Linear(256,num_outputs)
        # dropout 层,这里的参数指 dropout 的概率
        self.dropout = torch.nn.Dropout(0.3)
        self.dropout2 = torch.nn.Dropout(0.5)
        # ReLU 层
        self.relu = torch.nn.ReLU()
    
    # 前向传播函数,这是一个拼接的过程,使用大量变量是为了避免混淆,不做过多讲解
    def forward(self, x): # x shape: (batch_size, 24, 307)
        # LSTM 层会传出其参数,这里用 _ 将其舍弃
        h, _ = self.rnn(x)
        # LSTM 层会传出 (batch_size, 24, num_hiddens) 个参数,故需要 reshape 后丢入全连接层
        h_r = h.reshape(-1,self.hidden_size*24)
        h_d = self.dropout(h_r)
        y = self.dense(h_d)
        drop_y = self.dropout2(y)
        a = self.relu(drop_y)
        y2 = self.dense2(a)
        return y2

可以看到,Pytorch建立一个模型较为清楚简单,具体使用可以参考文档。

Pytorch 在使用 GPU 和 CPU 上的写法有所不同。在需要将保存在内存中的数据在 GPU 上运行时,需要主动将数据和模型拷贝到显存。

为了简化差异,我们使用一个布尔值:use_gpu 来判断是否可用 GPU ,从而淡化差异。这样就不需要写两份代码。

# 判断 gpu 是否可用
use_gpu = torch.cuda.is_available()

# 另一种写法是固定 device,每次调用数据都 to(device)即可
# device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

2.3.3 评估函数建立

这里给出了评估使用的函数,可以自测以获得信息。

评估指标为误差和的评分表映射值。其中
误差和(error_score)=均方根误差(RMSE)+平均绝对误差(MAE)

我们可以根据建立误差和的评估函数

def compute_mae(y_hat, y):
    '''
    :param y: 标准值
    :param y_hat: 用户的预测值
    :return: MAE 平均绝对误差 mean(|y*-y|)
    '''
    return torch.mean(torch.abs(y_hat - y))


def compute_rmse(y_hat, y):
    '''
    :param y: 标准值
    :param y_hat: 用户的预测值
    :return: RMSE 均方根误差 sqrt(mean((y*-y)^2))
    '''
    return torch.sqrt(torch.mean(torch.pow(y_hat - y, 2)))

下面描绘评估函数,输入 DataLoader 和用户的模型,返回对应的 MAE 和 RMSE 。

def evaluate_accuracy(data_iter, model):
    '''
    :param data_iter: 输入的 DataLoader
    :param model: 用户的模型
    :return: 对应的 MAE 和 RMSE
    '''
    # 初始化参数
    mae_sum, rmse_sum, n = 0.0, 0.0, 0
    
    # 对每一个 data_iter 的每一个 x,y 进行计算
    for x, y in data_iter:
        
        # 如果运行在 GPU 上,需要将内存中的 x 拷贝到显存中
        if (use_gpu):
            x=x.cuda()
            
        # 计算模型得出的 y_hat
        y_hat = model(x)
        
        # 将 y_hat 逆归一化,这里逆归一化需要将数据转移到 CPU 才可以进行
        y_hat_real = torch.from_numpy(scaler.inverse_transform(np.array(y_hat.detach().cpu()).reshape(y_hat.shape)))
        y_real = torch.from_numpy(scaler.inverse_transform(np.array(y).reshape(y.shape)))
        
        # 计算对应的 MAE 和 RMSE 对应的和,并乘以 batch 大小
        mae_sum += compute_mae(y_hat_real,y_real) * y.shape[0]
        rmse_sum += compute_rmse(y_hat_real,y_real) * y.shape[0]
        
        # n 用于统计 DataLoader 中一共有多少数量
        n += y.shape[0]
        
    # 返回时需要除以 batch 大小,得到平均值
    return mae_sum / n, rmse_sum / n

2.3.4 模型训练

首先我们需要选取优化器和损失函数。

Pytorch 使用的优化器和损失函数可以选用其提供的,也可以自己写。一般来说, Pytorch 自带的具有更好的数值稳定性,这里给出参考。

# 使用均方根误差
loss = torch.nn.MSELoss()

# 自定义的损失函数,可以直接调用
def my_loss_func(y_hat, y):
    return compute_mae(y_hat, y)

Pytorch 的优化器需要提供 model 的 parameters ,故需要先定义网络。

# 使用上面描述的线性网络
model = LinearNet(num_inputs,num_outputs)

# 使用 Adam 优化器, learning rate 调至 0.0001
optimizer = torch.optim.Adam(model.parameters(), lr=1e-4)

# 也可选用 SGD 或其他优化器
# optimizer = torch.optim.SGD(model.parameters(), lr=1e-4, momentum=0.9, weight_decay=0.1)

下面是训练函数。用于模型的直接训练。

def train_model(model, train_iter, test_iter, loss, num_epochs,
          params=None, optimizer=None):
    
    # 用于绘图用的信息
    train_losses, valid_losses, train_maes, train_rmses, valid_maes, valid_rmses = [], [], [], [], [], []
    
    # 循环 num_epochs 次
    for epoch in range(num_epochs):
        # 初始化参数
        train_l_sum, n = 0.0, 0
        # 初始化时间
        start = time.time()
        # 模型改为训练状态,如果使用了 dropout, batchnorm 之类的层时,训练状态和评估状态的表现会有巨大差别
        model.train()
        
        # 对训练数据集的每个 batch 执行
        for x, y in train_iter:
            
            # 如果使用了 GPU 则拷贝进显存
            if (use_gpu):
                x,y = x.cuda(),y.cuda()
            
            # 计算 y_hat
            y_hat = model(x)
            
            # 计算损失
            l = loss(y_hat, y).mean()

            # 梯度清零
            optimizer.zero_grad()
            
            # L1 正则化
            # for param in params:
            #     l += torch.sum(torch.abs(param))
            
            # L2 正则化可以在 optimizer 上加入 weight_decay 的方式加入

            # 求好对应的梯度
            l.backward()

            # 执行一次反向传播
            optimizer.step()

            # 对 loss 求和(在下面打印出来)
            train_l_sum += l.item() * y.shape[0]
            
            # 计数一共有多少个元素
            n += y.shape[0]
            
        # 模型开启预测状态
        model.eval()
        
        # 同样的,我们可以计算验证集上的 loss
        valid_l_sum, valid_n = 0, 0
        for x, y in valid_iter:
            # 如果使用了 GPU 则拷贝进显存
            if (use_gpu):
                x,y = x.cuda(),y.cuda()
            
            # 计算 y_hat
            y_hat = model(x)
            
            # 计算损失
            l = loss(y_hat, y).mean()

            # 对 loss 求和(在下面打印出来)
            valid_l_sum += l.item() * y.shape[0]
            
            # 计数一共有多少个元素
            valid_n += y.shape[0]
        
        # 对验证集合求指标
        # 这里训练集其实可以在循环内高效地直接算出,这里为了代码的可读性牺牲了效率
        train_mae, train_rmse = evaluate_accuracy(train_iter, model)
        valid_mae, valid_rmse = evaluate_accuracy(valid_iter, model)
        print('epoch %d, train loss %.4f, valid loss %.4f, train mae,rmse %.3f,%.3f, valid mae,rmse %.3f,%.3f, time %.2f sec'
              % (epoch + 1, train_l_sum / n, valid_l_sum / valid_n, train_mae, train_rmse, valid_mae, valid_rmse, time.time() - start))
        
        # 记录绘图有关的信息
        train_losses.append(train_l_sum / n)
        valid_losses.append(valid_l_sum / valid_n)
        train_maes.append(train_mae)
        train_rmses.append(train_rmse)
        valid_maes.append(valid_mae)
        valid_rmses.append(valid_rmse)
        
    # 返回一个训练好的模型和用于绘图的集合
    return model, (train_losses, valid_losses, train_maes, train_rmses, valid_maes, valid_rmses)

下面进行正式的模型训练,但是这里的模型训练在这里的 Notebook(CPU) 上要耗费非常长的时间(单 epoch 约 200 秒),建议使用离线任务中的 GPU 完成该步骤。将对应的数据保存到 results 文件夹中,在 Notebook 中读取并绘图。

# 训练模型
model, (train_losses, valid_losses, train_maes, train_rmses, valid_maes, valid_rmses) = train_model(model, train_iter, test_iter, loss , 5, model.parameters(), optimizer)

epoch 1, train loss 0.0261, valid loss 0.0117, train mae,rmse 31.207,44.126, valid mae,rmse 34.629,48.522, time 5.62 sec
epoch 2, train loss 0.0082, valid loss 0.0096, train mae,rmse 27.859,39.609,valid mae,rmse 31.206,43.775, time 5.60 sec
epoch 3, train loss 0.0071, valid loss 0.0090, train mae,rmse 27.217,38.310, valid mae,rmse 30.621,42.526, time 5.37 sec
epoch 4, train loss 0.0066,valid loss 0.0085, train mae,rmse 26.380,37.085, valid mae,rmse 29.856,41.387, time 5.70 sec
epoch 5, train loss 0.0062, valid loss 0.0083, train mae,rmse 26.166,36.545, valid mae,rmse 29.635,40.989, time 5.19 sec

可以直接使用 numpy 保存并读取。

# 为了方便储存与读取,建立成一个元组
draw_data = (train_losses, valid_losses, train_maes, train_rmses, valid_maes, valid_rmses)
# 记录保存路径
save_path = 'results/datas.npz'
# 保存到硬盘
np.savez(save_path, draw_data=draw_data)
# 读取数据
draw_data = np.load(save_path)['draw_data']
# 提取其中的数据
(train_losses, valid_losses, train_maes, train_rmses, valid_maes, valid_rmses) = draw_data

2.3.5 模型的评估

首先绘制训练图像,以供观测,下面绘制 loss 图像。

# 新建一个图像
plt.figure(figsize=(16,8))

# 绘制 train_loss 曲线
plt.plot(train_losses, label='train_loss')

# 绘制 valid_loss 曲线
plt.plot(valid_losses, label='valid_loss')

# 展示带标签的图像
plt.legend();

下面绘制 MAE 与 RMSE 在 epoch 中的变化。

# 新建一个图像
plt.figure(figsize=(16,8))

# 绘画结点
plt.plot(train_maes, c='blue', label='train_mae')

plt.plot(train_rmses, c='red', label='train_rmse')

plt.plot(valid_maes, c='green', label='valid_mae')

plt.plot(valid_rmses, c='orange', label='valid_rmse')

# 展示图像
plt.legend();

下面绘制结点 5 在校验集中与真实值的差距。这里仅考虑 Notebook(CPU) , GPU 版本的需要稍加修改。

# 新建一个图像
plt.figure(figsize=(16,8))

# 预测结果
y_hat = model(x_test).detach()

# 取前288个测试集
num_for_draw = 288

# 绘画某些结点第一天的情况
plt.plot(scaler.inverse_transform(y_test[:num_for_draw,5].reshape(-1,1)).reshape(-1), c='blue', label='y_test')

plt.plot(scaler.inverse_transform(y_hat[:num_for_draw,5].reshape(-1,1)).reshape(-1), c='red', label='y_hat')

# 展示图像
plt.legend();

当在校验集上取得较为满意的结果的时候,可以来到测试集一试。

# 获得测试集的数据
test_mae, test_rmse = evaluate_accuracy(test_iter, model)

print('test mae,rmse: %.3f,%.3f' % (test_mae,test_rmse))

在测试集也能取得满意结果的时候,可以在平台上测试并提交。

2.3.6 保存和读取模型

下面介绍保存和读取模型。模型应当保存在results文件夹下。

# 设计目录
model_path = 'results/mymodel.pt'
# 保存模型
torch.save(model.state_dict(), model_path)

读取模型

# 指定目录
model_path = 'results/mymodel.pt'
# 选用使用的模型类
model = LinearNet(num_inputs,num_outputs)
# 读入对应的参数
model.load_state_dict(torch.load(model_path))
# 
model.eval()

3.模型训练与提交

3.1 训练模型

模型训练时请主要在 GPU 上训练,在平台上可以使用离线任务 GPU 完成,并将模型保存到 results 文件夹中,并在模型预测时读取。

def train():
    '''训练模型
    :return: model 一个训练好的模型
    '''
    
    model = None
    # --------------------------- 此处下方加入训练模型相关代码 -------------------------------
    
    
    
    
    
    # 如果使用的不是 pytorch 框架,还需要改动下面的代码
    # 模型保存的位置
    model_path = 'results/mymodel.pt'
    # 保存模型
    torch.save(model.state_dict(), model_path)
    # --------------------------- 此处上方加入训练模型相关代码 -------------------------------
    
    
    
    return model

本赛题并不严格限定使用的框架,可以使用 Pytorch , Tensorflow 或其他框架。只需训练好模型并保存,并在下文中写入合适的读取模型并实现预测即可。测试和评估程序会直接调用 predict(test_x) 函数
注意,模型预测 x.shape[0]==288 的数据不能超过 5 分钟,否则将被记为超时。
模型返回的类型必须是 numpy 数组类型。

# 这里提供了 torch 和 numpy 的互转

x_torch = torch.empty(3,5)
print(type(x_torch))

# torch to numpy
x_numpy = x_torch.numpy()
x_numpy_v2 = np.array(x_torch)
print(type(x_numpy))
print(type(x_numpy_v2))

# numpy to torch
x_torch_v2 = torch.from_numpy(x_numpy)
print(type(x_torch_v2))

3.2 模型提交

在下方规定区域内写入加载模型的方式,该函数是在被测试和评估时调用的预测函数。注意,为了便于用户使用各种框架,输出的数组必须为 numpy 数组。

在测试和评估时为 CPU 运行环境。

注意:

  1. 点击左侧栏提交结果后点击生成文件则只需勾选定义模型 class 和 实例化模型的 cell,即【模型预测代码答题区域】的 cell。
  2. 请导入必要的包和第三方库 (包括此文件中曾经导入过的)。
  3. 请加载你认为训练最佳的模型,并按要求填写模型路径。
  4. 请不要改动 predict 函数的输入输出格式与类型,并将所有需要提交的文件勾选上。
  5. 作业测试时记得填写你的模型路径及名称, 如果采用 离线任务 请将模型保存在 results 文件夹下。
#######################################################################
## 此处为需要提交的代码的cell,请参考下列流程实现你自己模型的 predict 函数,
## 请不要修改 predict 函数的输入输出格式、类型!!
#######################################################################
def predict(test_x):
    '''对于给定的 x 预测未来的 y 。
    :param test_x: 给定的数据集合 x ,对于其中的每一个元素需要预测对应的 y 。
    :return: test_y 对于每一个 test_x 中的元素,给出一个对后五分钟流量情况的预测。
    '''
    # test 的数目
    n_test = test_x.shape[0]
    
    test_y = None
    
    model = None
    # 模型保存的位置
    model_path = 'results/mymodel.pt'
    # --------------------------- 此处下方加入读入模型和预测相关代码 -------------------------------
    # 读取模型
    model = LinearNet(num_inputs,num_outputs)
    model.load_state_dict(torch.load(model_path))
    model.eval()
    # 如果使用的不是 pytorch 框架,还需要改动上面的代码
    
    
    # --------------------------- 此处上方加入读入模型和预测相关代码 -------------------------------
    
    # 保证输出的是一个 numpy 数组
    assert(type(test_y) == np.ndarray)
    
    # 保证 test_y 的 shape 正确
    assert(test_y.shape == (n_test,307))
    
    return test_y

jupter和数据集

你可能感兴趣的:(python,机器学习,数据挖掘)