[排名前5%解法] 2024 Datawhale AI夏令营 Task1:基于自动机器学习AutoGluon进行产量预测

#Datawhale AI夏令营 #物质科学赛道 #机器学习思路 #AutoGluon自动学习方法 #TOP5%解法

本文从一个学习者的视角,详细叙述物质科学赛道的研究背景与研究方法,并着重介绍自动机器学习autogluon的基本原理和基于autogluon自动机器学习进行产率预测的实现方法

你好! 这是我第一次参加AI相关的赛事,和很多刚刚接触AI赛事的小白一样,在面对Task1的时候,一开始我也是一脸懵逼的。
在这里插入图片描述

在经历了两天左右的探索之后,我了解到了物质科学赛道产率预测的实践背景,并尝试使用了多种机器学习方法进行预测,单个机器学习方法虽然有效但在大佬云集的排行榜上则略显逊色了。之后,我尝试进行了基于贝叶斯优化的超参数调优和模型集成,但还是难以与诸位大佬的深度强化学习DNN方法,大模型方法等高级方法一较高下。

在这里插入图片描述

在此基础上,我尝试进一步使用自动机器学习方法,综合超参数调优,模型集成等方法的优势,使用传统的机器学习方法,结合自动机器学习技术,在计算性能受限,模型层数受到严重限制的条件下(没钱,免费的老是爆内存爆显存。。。),仍然取得了前5%的排名。在此,我希望与你分享我在Task1上的探索过程。

下面,本文将分为四个部分介绍本次比赛的探索内容,主要分为研究背景,baseline代码详解,autogluon自动机器学习的原理,基于autogluon自动机器学习和分子指纹的产率预测的代码详解。

研究背景

碳氮成键反应、Diels-Alder环加成反应等一系列催化合成反应,被广泛应用于在各类药物的生产合成过程中。研究人员与产业界在针对特定反应类型开发新的催化合成方法时,往往追求以高产率获得目标产物,也即开发高活性的催化反应体系,以提升原子经济性,减少资源的浪费与环境污染。然而,开发具有高活性的催化反应体系通常需要对包括催化剂和溶剂在内的多种反应条件进行详尽的探索,这导致了它成为了一项极为耗时且资源密集的任务。这要求对包括催化剂和溶剂在内的多种反应条件进行详尽的探索。目前,反应条件的筛选在很大程度上依赖于经验判断和偶然发现,导致催化反应条件的优化过程既耗时又费力,并且严重制约了新的高效催化合成策略的开发。

反应底物和反应条件是决定其产率的关键因素。因此,我们可以利用AI模型来捕捉底物、条件与产率之间的内在联系。借助产率预测AI模型,仅需输入底物和条件的信息,我们就能够预测该反应组合下的产率,从而有效提升催化反应的条件筛选效率。

引用:http://competition.sais.com.cn/competitionDetail/532233/competitionData

在这里插入图片描述

baseline代码详解

1.安装依赖

安装依赖就不用说了,主要是rdkit不是很熟悉,在这里,安装rdkit主要是为了把SMILES化学式转化为分子指纹,从而进一步作为训练预测器的训练数据。(emm,化学领域分子特征提取优化方法其实不是特别懂,有更好的方法嘛,欢迎化学专业大佬在评论区留言)

!pip install pandas
!pip install -U scikit-learn
!pip install rdkit
# 首先,导入库
import pickle
import pandas as pd
from tqdm import tqdm
from sklearn.ensemble import RandomForestRegressor
from rdkit.Chem import rdMolDescriptors
from rdkit import RDLogger,Chem
import numpy as np
RDLogger.DisableLog('rdApp.*')

2.读取数据,将SMILES化学式转化为分子指纹

就是用pandas读入数据,然后用rdkit转化为分子指纹就好了

SMILES

SMILES,全称是Simplified Molecular Input Line Entry System,是一种将化学分子用ASCII字符表示的方法,是化学信息学领域非常重要的工具。

由于Reactant1,Reactant2,Product,Additive,Solvent都是由SMILES表示。所以,可以使用rdkit工具直接提取SMILES的分子指纹(向量),作为特征。

Morgan fingerprint

位向量(bit ector)形式的特征,即由0,1组成的向量。

RDKit

化学信息学中主要的工具,开源。网址:http://www.rdkit.org,支持WIN\MAC\Linux,可以被python、Java、C调用。几乎所有的与化学信息学相关的内容都可以在上面找到。

引用:Datawhale的 baseline代码说明

(1)定义转化函数

def mfgen(mol,nBits=2048, radius=2):
    '''
    Parameters
    ----------
    mol : mol
        RDKit mol object.
    nBits : int
        Number of bits for the fingerprint.
    radius : int
        Radius of the Morgan fingerprint.
    Returns
    -------
    mf_desc_map : ndarray
        ndarray of molecular fingerprint descriptors.
    '''
    # 返回分子的位向量形式的Morgan fingerprint
    fp = rdMolDescriptors.GetMorganFingerprintAsBitVect(mol,radius=radius,nBits=nBits)
    return np.array(list(map(eval,list(fp.ToBitString()))))

# 加载数据
def vec_cpd_lst(smi_lst):
    smi_set = list(set(smi_lst))
    smi_vec_map = {}
    for smi in tqdm(smi_set): # tqdm:显示进度条
        mol = Chem.MolFromSmiles(smi)
        smi_vec_map[smi] = mfgen(mol)
    smi_vec_map[''] = np.zeros(2048)
    
    vec_lst = [smi_vec_map[smi] for smi in smi_lst]
    return np.array(vec_lst)

(2)读取数据

dataset_dir路径不同在线平台不同

dataset_dir = '../dataset'   # # 注:如果是在AI Studio上,将这里改为'dataset'

train_df = pd.read_csv(f'{dataset_dir}/round1_train_data.csv')
test_df = pd.read_csv(f'{dataset_dir}/round1_test_data.csv')

print(f'Training set size: {len(train_df)}, test set size: {len(test_df)}')

(3)转化数据

# 从csv中读取数据
train_rct1_smi = train_df['Reactant1'].to_list()
train_rct2_smi = train_df['Reactant2'].to_list()
train_add_smi = train_df['Additive'].to_list()
train_sol_smi = train_df['Solvent'].to_list()

# 将SMILES转化为分子指纹
train_rct1_fp = vec_cpd_lst(train_rct1_smi)
train_rct2_fp = vec_cpd_lst(train_rct2_smi)
train_add_fp = vec_cpd_lst(train_add_smi)
train_sol_fp = vec_cpd_lst(train_sol_smi)
# 在dim=1维度进行拼接。即:将一条数据的Reactant1,Reactant2,Product,Additive,Solvent字段的morgan fingerprint拼接为一个向量。
train_x = np.concatenate([train_rct1_fp,train_rct2_fp,train_add_fp,train_sol_fp],axis=1)
train_y = train_df['Yield'].to_numpy()

# 测试集也进行同样的操作
test_rct1_smi = test_df['Reactant1'].to_list()
test_rct2_smi = test_df['Reactant2'].to_list()
test_add_smi = test_df['Additive'].to_list()
test_sol_smi = test_df['Solvent'].to_list()

test_rct1_fp = vec_cpd_lst(test_rct1_smi)
test_rct2_fp = vec_cpd_lst(test_rct2_smi)
test_add_fp = vec_cpd_lst(test_add_smi)
test_sol_fp = vec_cpd_lst(test_sol_smi)
test_x = np.concatenate([test_rct1_fp,test_rct2_fp,test_add_fp,test_sol_fp],axis=1)

3.训练模型,保存模型,加载模型

(1)训练模型

baseline中直接使用训练集进行训练,然后就用测试集测试了,这样当然是不合理的,是留给学员们加以改进而故意设计的。一般的做法是划分训练集,测试集与验证集,在训练集上训练,在验证集上调参,最终在测试集中获得模型的最终评分!

至于使用什么模型,初学阶段可以尝试使用xgboost,lightgbm,catboost等常用模型,在实际使用过程中,我们通常是直接调包,再去了解模型背后的数学原理。(勿)

此外,使用一定的方法进行超参数调优和模型集成也是十分重要的,常用的超参数调优有贝叶斯优化、HPO方法等,常用的模型集成方法有软投票、bagging、stacking等。

在这里插入图片描述

# Model fitting
model = RandomForestRegressor(n_estimators=10,max_depth=10,min_samples_split=2,min_samples_leaf=1,n_jobs=-1) # 实例化模型,并指定重要参数
model.fit(train_x,train_y) # 训练模型

(2)保存模型

# 保存模型
with open('./random_forest_model.pkl', 'wb') as file:
    pickle.dump(model, file)

(3)加载模型与预测

# 加载模型
with open('random_forest_model.pkl', 'rb') as file:
    loaded_model = pickle.load(file)

# 预测\推理
test_pred = loaded_model.predict(test_x)

4.生成比赛提交的文件

ans_str_lst = ['rxnid,Yield']
for idx,y in enumerate(test_pred):
    ans_str_lst.append(f'test{idx+1},{y:.4f}')
with open('./submit.txt','w') as fw:
    fw.writelines('\n'.join(ans_str_lst))

autogluon的基本原理

1.autogluon的基本思路

autogluon是建立在automl框架的基础上的,automl期望通过自动超参数调优和特征工程,提高机器学习使用过程中的便利程度。
而autogluon的基本思路,用沐神(autogluon的作者之一)的一句话来说,就是找十个臭皮匠(不需要大量调参),希望十个臭皮匠一起打败一个诸葛亮。
在这里插入图片描述

2.stacking技术

在多个模型之上增加一个线性层,通过训练得到各个模型的权重,通过加权平均获得更好的预测结果。

3.K折交叉的bagging技术

先进行K折交叉验证,再多个K折模型的输出作平均得到最终的预测结果。

4.多层stacking技术

每一层进行K折交叉验证的bagging技术,再将每层多个模型的输出和输入结合起来再做一次预测,最终通过一个线性层加权平均输出。

  1. 基础层模型(Level 0)
    • 在最底层,Autogluon会使用多种不同的机器学习算法。这些算法可以是传统的机器学习算法,如随机森林、梯度提升机(例如XGBoost、LightGBM),也可以是深度学习模型。
    • 每个模型都在训练数据上独立训练,并做出自己的预测。
  2. 元模型(Meta-Model)
    • 在Stacking的第一层(也称为元学习层或次级学习层),这些基础模型的输出被用作输入来训练一个元模型(通常是一个简单的线性模型或轻量级的树模型)。
    • 元模型的目的是学习如何最佳地结合基础模型的预测,以产生更准确的最终预测。
  3. 多层Stacking
    • 在多层Stacking中,可以将第一层的元模型再作为基础模型,它们的输出又可以被用来训练一个新的元模型,这样形成了一个层次结构。
    • 这种结构可以继续扩展,形成更多层次,每一层都试图纠正前一层模型的错误,进一步提高整体的预测性能。

注:多层stacking虽好,但如果你在使用免费的GPU环境,比如kaggle或colab,在本次实验的数据集中,可能是要爆内存或爆显存的,所以要么设置不使用多层stacking,要么就采用一定的手段,及时删除效果不佳的模型,为最终的模型预测节省空间。

引用:https://www.bilibili.com/video/BV1F84y1F7Ps/?spm_id_from=333.788&vd_source=37b3dcdff8e118c3ac63e7b31d81dbe1

autogluon的实践代码

在搞明白autogluon的基本原理以后,下面我们基于baseline的预处理结果进行进一步的预测,在此基础上代码就非常简单了
(由于比赛尚未结束,本文给出一种无调优的基础baseline,大概可以排到前10%,在比赛结束以后,本文将第一时间公布前5%的优化代码)

在之前的baseline代码中,我们获得了成功转化的宝贵数据
train_x, train_y,test_x
下面,我们基于这三个数组,利用autogluon生成一个高规格的baseline代码:

1.读入数据

import pandas as pd
df = pd.concat([pd.DataFrame(train_x),pd.DataFrame(train_y,columns=['label'])], axis=1)
df

2.训练模型

from autogluon.tabular import TabularDataset,TabularPredictor
train_data = TabularDataset(df)
label = 'label'
predictor = TabularPredictor(label=label).fit(train_data)

3.进行预测

df_x_test = pd.DataFrame(test_x)
test_data = TabularDataset(df_x_test)
preds = predictor.predict(test_data)
preds

4.生成竞赛所需的txt文件

ans_str_lst = ['rxnid,Yield']
for idx,y in enumerate(preds):
    ans_str_lst.append(f'test{idx+1},{y:.4f}')
with open('./submit.txt','w') as fw:
    fw.writelines('\n'.join(ans_str_lst))

最终的竞赛评分为0.36左右,在全部300多位选手中排名前30,基本达到了预期目标。
笔者水平有限,欢迎各位大佬批判指正!
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

虢叔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值