Datawhale AI 夏令营 催化反应产率预测 Task2
转移到云端
之前在本地配置了pytorch
+sklearn
环境,但是发现在本地运行 Baseline 中
的 RNN 网络速度还是很慢,平均一个 epoch 要耗时 10 分钟左右,对于后续的调参和模型集成上都是极为不利的。
因此,借助于本次 DataWhale 推荐的 魔搭 平台,主要由以下几个优点:
- 不用担心环境配置问题,之前在本地上需要手动一个一个安装包,还有可能遇到
环境依赖问题,在云服务器上有配置好的pytorch
环境 - GPU 速度快,可以节约大量的时间,新用户可以享受 100 小时的免费 GPU 使用时长
- 不用听本地电脑运行巨大的噪声,省心省力
魔搭平台的具体使用方法在 DataWhale 中已经详细介绍过了,在此按下不表;
从 Task1 过渡到 Task2, 需要下载 Task2_RNN.ipynb
文件和 vocab_full.txt
,分别放置在 Task1 中的 mp/code
和 mp
文件夹下,同时可以在mp
文件夹下新建output
文件夹和 model
文件夹,否则在 Task2_RNN.ipynb
运行中就会因为找不到文件而报错。
然后就可以丝滑的运行 Baseline 哩!
Baseline
Baseline 的代码在 Task2_RNN.ipynb
中,代码中已经详细注释了,可以按照注释中的步骤进行运行。
发现 Baseline 中的代码虽然包含了机器学习过程中较为完整的 模型定义,模型训练,submit.txt
文件生成,但是在模型选择和参数调优上
做的不太够。我在 Baseline 上做了一些修改:
- 将训练数据(即含有特征+标签的数据)划分为训练集和验证集,在训练
过程中,可以查看模型在验证集上的表现,从而提前发现模型过拟合的情况,从而减少模型训练时间。 - 增加
R
2
R^2
R2 评估指标,可以在训练过程中查看模型在训练集和验证集上的
r2_score
划分训练集和验证集
在train
函数中作以下修改:
train_size = int(0.8 * len(dataset))
valid_size = len(dataset) - train_size
train_dataset, valid_dataset = torch.utils.data.random_split(dataset, lengths=[train_size, valid_size])
train_loader = DataLoader(train_dataset, batch_size=BATCH_SIZE, shuffle=True, collate_fn=collate_fn)
valid_loader = DataLoader(valid_dataset, batch_size=BATCH_SIZE, shuffle=True, collate_fn=collate_fn)
也就是先计算训练集和验证集的大小,然后使用torch.utils.data.random_split
函数将数据集划分成训练集和验证集,最后使用DataLoader
函数将训练集和验证集分别封装成DataLoader
对象。
进一步可以使用 k k k 折交叉验证的方法,将训练集划分成 k k k 个子集,每次使用 k − 1 k-1 k−1 个子集作为训练集,剩余一个子集作为验证集,重复 k k k 次,取平均值作为最终的评估结果。
但是带来的肯定是时间的大幅增加,因此就摆烂了。
然后利用训练好的模型直接在验证集上评估:
with torch.no_grad():
for i, (src, y) in tqdm(enumerate(valid_loader), total=len(valid_loader) // BATCH_SIZE):
src, y = src.to(device), y.to(device)
output = model(src)
valid_score += r2_score( y.detach().cpu().numpy(), output.detach().cpu().numpy())
valid_score_in_a_epoch = valid_score / len(valid_loader)
打印每个 epoch 上的值:
print(f'Epoch: {epoch+1:02} | Train Loss: {loss_in_a_epoch:.3f} | Train Score: {train_score_in_a_epoch} | Valid Score: {valid_score_in_a_epoch}')
顺便调整一下 Baseline 中的代码,尽可能保存好的模型:
if loss_in_a_epoch < best_loss:
# 在训练循环结束后保存模型
torch.save(model.state_dict(), f'../model/RNN_H_epoch{epoch}.pth')
best_loss = loss_in_a_epoch
r2_score 中指标计算
在最开始的单元格中导入 sklearn
:
from sklearn.metrics import r2_score
使用 sklearn
中的 r2_score
函数计算:
train_score += r2_score(y.detach().cpu().numpy(), output.detach().cpu().numpy())
train_score_in_a_epoch = train_score / len(train_loader)
valid_score += r2_score( y.detach().cpu().numpy(), output.detach().cpu().numpy())
valid_score_in_a_epoch = valid_score / len(valid_loader)
关于结果
可能是 RNN 模型本身的问题,多次调整超参数,最好的结果也只有 0.10 左右,最后也不出意外的产生了过拟合;但是使用 LSTM 模型,可以达到
0.25左右的效果,貌似还行。