1. 引言
1.1. 分子性质预测概述
分子性质预测是计算机辅助药物发现流程中至关重要的任务之一,它在许多下游应用如药物筛选和药物设计中发挥着核心作用:
1.1.1. 目的与重要性:
- 分子性质预测旨在通过分子内部信息(如原子坐标、原子序数等)对分子的物理和化学性质进行预测。
- 这有助于快速从大量候选化合物中筛选出符合特定性质的化合物,从而加速药物筛选和设计的流程。
1.1.2. 传统方法:
- 密度泛函理论(DFT)是传统的分子性质预测方法,它精确但计算耗时,通常需要数小时才能完成单个分子的性质计算。
- 由于候选化合物数量庞大,使用DFT进行预测需要巨大的资源和时间成本。
1.1.3. 深度学习在分子性质预测中的应用:
- 得益于深度学习的快速发展,越来越多的研究者开始尝试将深度学习应用于分子性质预测领域。
- 神经网络模型能够从数据中自行学习合适的特征表示,不需要依赖人工构建的特征(如指纹与描述符)。
- 深度学习模型能够处理复杂的分子结构信息,并自动提取分子特征,从而提高了预测的准确性。
1.1.4. 主流的基于ML的分子性质预测方法:
- 基于描述符的方法:对分子特征进行人工提取,其质量对预测结果有重要影响。
- 基于图的方法:将分子描述为具有节点(原子)和边(键)的图结构,利用图神经网络(GNN)进行特征提取。这种方法能够避免人工提取描述符过程中的信息丢失,但严重依赖于数据量。
- 基于SMILES的方法:将分子性质预测看作自然语言处理(NLP)问题,直接从SMILES字符串中提取分子特征。这种方法对特征提取能力和数据量有更高要求。
- 分子性质预测方法中的消息传递神经网络(MPNN)是一种重要的技术,它特别适用于处理图结构数据,如分子结构中的原子和化学键。
1.1.5. 挑战与未来方向:
- 尽管深度学习在分子性质预测中取得了显著进展,但仍面临一些挑战,如数据稀疏性、模型可解释性等。
- 未来研究将致力于开发更先进的模型架构和算法,以提高预测准确性、降低计算成本,并探索更多应用场景。
分子性质预测是药物发现和设计中不可或缺的一环。随着深度学习技术的不断发展,我们有理由相信未来的分子性质预测将更加高效、准确和智能化。
1.2 消息传递神经网络(MPNN)
消息传递神经网络(MPNN)是一种重要的图神经网络(GNN)框架,特别适用于处理具有图结构的数据,如社交网络、化学分子等。
1.2.1. MPNN的基本原理
- MPNN的核心思想是通过节点之间的消息传递来更新节点的特征表示。在每一步的消息传递过程中,节点会接收来自邻居节点的信息,并利用这些信息来更新自身的特征表示。
- 通过多轮的消息传递,节点之间的信息能够得到充分的交流和融合,从而使得整个图的结构和节点特征得到更精细的表示。
1.2.2. MPNN的模型结构
- MPNN的模型结构通常包括输入层、消息传递层和输出层。
- 输入层:负责将原始的节点特征和图结构信息转化为可处理的神经网络输入。
- 消息传递层:是MPNN的核心部分,它通过多轮的消息传递来更新节点的特征表示。每个节点都会接收来自邻居节点的消息,并根据这些消息来更新自身的特征表示。具体的更新方式可以通过一种或多种不同的更新函数来实现,如加权平均、最大池化等。
- 输出层:将最终的节点特征表示转化为具体的任务输出。
1.2.3. MPNN的应用场景
- MPNN在分子特性预测方面有着广泛的应用。由于分子可以被视为一种特殊的图结构,其中原子是节点,化学键是边,MPNN能够很好地处理这种结构数据。例如,MPNN可以用于预测分子的血脑屏障通透性、溶解度等性质。
1.2.4. MPNN的优势
- MPNN能够处理具有不同大小和结构的图数据,因此具有高度的灵活性和可扩展性。
- 通过迭代地传递和聚合信息,MPNN能够捕获图的全局结构信息,从而得到更精细的节点表示。
- MPNN的模型结构相对简单,易于实现和调试。
1.2.5. MPNN的未来发展
- 随着图神经网络技术的不断发展,MPNN的性能和应用场景也将得到进一步的拓展。例如,可以探索将MPNN与其他深度学习模型结合使用,以进一步提高其性能;或者将MPNN应用于更广泛的领域,如社交网络分析、推荐系统等。
消息传递神经网络(MPNN)是一种强大的图神经网络框架,它通过节点之间的消息传递来更新节点的特征表示,具有高度的灵活性和可扩展性。在分子特性预测等领域有着广泛的应用前景。
1.3. MPNN用于分子预测的优势和局限
1.3.1.MPNN在分子预测方面的优势
-
自然处理图结构数据:MPNN是专为处理图结构数据设计的,分子作为图结构数据的一种,其中原子作为节点,化学键作为边,使得MPNN能够自然且高效地处理分子数据。
-
全局结构信息的捕获:MPNN通过迭代地传递和聚合节点间的信息,能够捕获分子的全局结构信息。这种能力使得MPNN在预测分子性质时,能够综合考虑分子内部各个部分之间的相互作用和整体结构,从而提高预测的准确性。
-
高度灵活性和可扩展性:MPNN不受分子大小或结构的限制,能够处理从简单有机分子到复杂生物大分子的各种情况。这种灵活性和可扩展性使得MPNN在分子预测领域具有广泛的应用前景。
-
良好的预测性能:MPNN在多个分子预测任务中均取得了良好的性能。例如,在预测分子的血脑屏障通透性、溶解度等性质时,MPNN能够准确地预测出分子的这些性质,为药物设计和筛选提供有力支持。
-
可解释性:MPNN的预测结果具有一定的可解释性。通过分析MPNN在预测过程中不同节点和边的贡献,可以了解哪些部分对预测结果的影响最大,从而提供对分子性质的深入理解。
1.3.2.MPNN在分子预测方面的局限性
-
数据依赖性:MPNN的性能在很大程度上取决于训练数据的数量和质量。在数据量不足或数据质量不高的情况下,MPNN的预测性能可能会受到影响。
-
计算复杂度: 对于大型复杂分子,MPNN的计算复杂度可能会较高,需要较长的计算时间。这可能会限制MPNN在实时或大规模分子预测任务中的应用。
-
模型复杂度:MPNN的模型结构相对复杂,需要较高的技术门槛和计算资源来设计和实现。这可能会增加MPNN在分子预测领域的应用难度和成本。
-
可解释性的局限性:尽管MPNN具有一定的可解释性,但其解释能力仍然有限。在某些情况下,MPNN可能无法提供足够详细的解释来完全理解其预测结果。
综上来看,MPNN在分子预测方面具有显著的优势,但也存在一些局限性。为了充分发挥MPNN的优势并克服其局限性,需要进一步探索和优化MPNN的模型结构和算法设计,并积累更多的训练数据和经验。
2. MPNN实现分子性质预测过程
2.1. 实现过程概述
本文讨论的方法基于消息传递神经网络(MPNN)实现预测分子血脑屏障通透性(BBBP)
2.1.1. 文章主要内容
在本文中我们将探索如何使用消息传递神经网络(MPNN)这一图神经网络(GNN)的变体来预测分子的一个重要属性——血脑屏障通透性(BBBP)。BBBP是评估药物能否穿过血脑屏障的关键指标,对于药物研发具有重大意义。
2.2.2. 研究的动机
分子可以被自然地建模为无向图G=(V, E),其中V代表顶点(或节点),对应于分子中的原子;E代表边,对应于原子之间的化学键。这种表示形式为利用图神经网络处理分子数据提供了便利。与基于预计算分子特征的传统方法(如随机森林、支持向量机等)相比,MPNN等GNN模型能够直接在图结构上进行操作,从而有可能捕获到更复杂的分子间关系,进而提升预测性能。
2.2.3.传统方法与GNN的比较
传统方法通常依赖于一系列预计算的分子特征,如分子量、极性、电荷和碳原子数量等。这些特征虽然已被证明是分子属性的有效预测器,但它们往往忽略了分子内部的复杂结构和相互作用。相比之下,GNN(如MPNN)能够直接在图的节点和边上进行操作,从而更全面地捕捉分子的结构和化学性质。
2.2.4.文章的内容
- 数据预处理:将分子数据集转换为图结构,并为每个节点和边提取相关特征。
- 定义MPNN模型:
- 设计消息函数,用于在节点之间传递信息。
- 设计更新函数,用于根据接收到的消息更新节点状态。
- 设计读出函数,用于从节点状态生成整个图的表示。
-
模型训练:使用标记的分子数据集训练MPNN模型,通过反向传播算法优化模型参数。
-
模型评估:在测试集上评估模型的性能,并使用适当的评估指标(如准确率、F1分数、AUC-PR等)来衡量预测效果。
-
模型调优:根据评估结果调整模型参数和架构,以优化预测性能。
2.2.软件准备
软件安装说明
为了开始我们的教程,首先需要安装RDKit和其他必要的依赖项。
RDKit是一个集化学信息学和机器学习软件于一体的工具集,使用C++和Python编写。在这个教程中,我们将利用RDKit将SMILES(简化分子输入行表示法)转换为分子对象,并从中提取原子和键的集合。
SMILES是一种将分子结构表达为ASCII字符串的方式。对于较小的分子,SMILES字符串是相对容易理解的。将分子编码为字符串既有助于减轻数据库和/或网络搜索的负担,又便于进行这些搜索。RDKit运用算法将给定的SMILES准确转换为分子对象,这些对象随后可用于计算大量的分子属性/特征。
通常情况下,RDKit通过Conda进行安装。但感谢rdkit_platform_wheels项目,我们现在可以更方便地通过pip来安装RDKit。以下是安装RDKit的步骤(注意:这里只是一个示例命令,具体命令可能因您的环境和需求而有所不同):
pip install rdkit-pypi
请确保您的Python环境已正确设置,并且您已经安装了所有必要的依赖项。此外,根据您的项目需求,您可能还需要安装其他科学计算库,如NumPy、SciPy、Pandas等,这些库可以通过类似的pip命令进行安装。
pip -q install pandas
pip -q install Pillow
pip -q install matplotlib
pip -q install pydot
sudo apt-get -qq install graphviz
在继续教程之前,请检查您的安装是否正确,并确认所有依赖项都已满足。如有需要,您可以查阅RDKit的官方文档或相关社区资源以获取更详细的安装指南和支持。
导入需要的安装包
import os
# Temporary suppress tf logs
os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3"
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import warnings
from rdkit import Chem
from rdkit import RDLogger
from rdkit.Chem.Draw import IPythonConsole
from rdkit.Chem.Draw import MolsToGridImage
# Temporary suppress warnings and RDKit logs
warnings.filterwarnings("ignore")
RDLogger.DisableLog("rdApp.*")
np.random.seed(42)
tf.random.set_seed(42)
2.3. 数据预处理
2.3.1. 下载数据集
段代码首先会尝试从指定的URL下载数据集(如果它尚未被下载到默认的Keras缓存目录)。然后,它会使用Pandas读取CSV文件,并选择第2、3和4列(因为usecols的索引是从0开始的)。最后,它会打印出索引为96到103的行。
import keras.utils
import pandas as pd
# 使用keras.utils.get_file下载数据集(如果尚未下载)
csv_path = keras.utils.get_file(
"BBBP.csv", "https://deepchemdata.s3-us-west-1.amazonaws.com/datasets/BBBP.csv"
)
# 使用pandas读取csv文件,并选择特定的列
df = pd.read_csv(csv_path, usecols=[1, 2, 3])
# 显示索引为96到103的行(注意Python中的索引是从0开始的)
print(df.iloc[96:104])
序号 | 分子名称 | p_np | SMILES字符串 |
---|---|---|---|
96 | 头孢西丁 | 1 | CO[C@]1(NC(=O)Cc2sccc2)[C@H]3SCC(=C(N3C1=O)C(O... |
97 | Org34167 | 1 | NC(CC=C)c1ccccc1c2noc3c2cccc3 |
98 | 9-羟基利培酮 | 1 | OC1C(N2CCC1)=NC(C)=C(CCN3CCC(CC3)c4c5ccc(F)cc5... |
99 | 醋氨酚(对乙酰氨基酚) | 1 | CC(=O)Nc1ccc(O)cc1 |
100 | 乙酰水杨酸(阿司匹林) | 0 | CC(=O)Oc1ccccc1C(O)=O |
101 | 别嘌醇 | 0 | O=C1N=CN=C2NNC=C12 |
102 | 前列地尔 | 0 | CCCCC[C@H](O)/C=C/[C@H]1[C@H](O)CC(=O)[C@@H]1C... |
103 | 氨茶碱 | 0 | CN1C(=O)N(C)c2nc[nH]c2C1=O.CN3C(=O)N(C)c4nc[nH]... |
注释:p_np渗透性标签 (1=能渗透, 0=不能渗透)
通过上述代码,我们下载了BBBP数据集:
数据集名称:血脑屏障渗透性(Blood-Brain Barrier Penetration, BBBP)数据集
来源:该数据集可以从MoleculeNet.org下载,相关信息可在《一种基于贝叶斯方法的计算机模拟血脑屏障渗透性建模》和《MoleculeNet:分子机器学习的基准》等文献中找到。
数据集概述:
- 数据量:包含2,050个分子样本。
- 特征:每个分子样本都包含以下信息:
- 名称:分子的唯一标识符或名称。
- SMILES字符串:表示分子结构的简化分子输入行表示法(Simplified Molecular Input Line Entry System)。
- 标签:每个分子样本都有一个二进制标签(1或0),表示该分子是否能够通过血脑屏障(BBB)。
研究背景:
血脑屏障(BBB)是分隔血液与大脑细胞外液的一层特殊膜,它的主要功能是保护大脑免受有害物质和病原体的侵害。然而,这也使得许多潜在的治疗中枢神经系统疾病的药物无法进入大脑。因此,对血脑屏障渗透性的研究对于开发能够针对中枢神经系统的新药物至关重要。
数据集用途:
该数据集可用于训练机器学习模型,以预测新分子的血脑屏障渗透性。通过准确的预测,研究人员可以更有效地筛选出具有潜在疗效的药物候选物,从而加速药物开发的进程。
2.3.2.特征定义
为了对分子中的原子和键进行特征编码,我们定义了两个类:AtomFeaturizer
和 BondFeaturizer
。
为了保持本教程的简洁和明了,我们仅选择了几个关键的(原子和键)特征进行介绍:对于原子,我们考虑其元素符号、价电子数、氢键数以及轨道杂化情况;对于键,我们关注其(共价)键的类型以及共轭状态。这些特征将有助于我们更好地描述分子结构,并在后续的机器学习模型中进行有效的特征表示。
import numpy as np
from rdkit import Chem
class Featurizer:
def __init__(self, allowable_sets):
self.dim = 0
self.features_mapping = {
}
for k, s in allowable_sets.items():
s = sorted(list(s))
self.features_mapping[k] = dict(zip(s, range(self.dim, len(s) + self.dim)))
self.dim += len(s)
def encode(self, inputs):
output = np.zeros((self.dim,))
for name_feature, feature_mapping in self.features_mapping.items():
feature = getattr(self, name_feature)(inputs)
if feature in feature_mapping:
output[feature_mapping[feature]] = 1.0
return output
class AtomFeaturizer(Featurizer):
def __init__(self, allowable_sets):
super().__init__(allowable_sets)
# allowable_sets 中至少包含 'symbol', 'n_valence', 'n_hydrogens', 'hybridization' 这几个键
# 对应的值应该是这些特征的可能取值集合
def symbol(self, atom):
# atom 是 RDKit 的 Atom 对象
return atom.GetSymbol()
def n_valence(self, atom):
# RDKit 的 Atom 对象有 GetTotalValence 方法
return atom.GetTotalValence()
def n_hydrogens(self, atom):
# RDKit 的 Atom 对象有 GetTotalNumHs 方法
return atom.GetTotalNumHs()
def hybridization(self, atom):
# GetHybridization 返回的是一个枚举类型,并且有 name 属性
hybridization_name = atom.GetHybridization().name
# 注意: name 是一个字符串,并且可能需要转换为小写
# 但有时枚举的 name 属性已经是大写或小写,或者可能不是完全小写,因此这个转换可能不是必要的
# 根据实际 RDKit 版本和枚举实现来确定是否需要转换
return hybridization_name.lower()
# 示例用法
# RDKit 的 Atom 对象 atom,以及一个定义允许特征集的字典 allowable_sets
# allowable_sets = {'symbol': set(['C', 'O', 'N', 'H']), 'n_valence': set([1, 2, 3, 4]), ...}
# atom_featurizer = AtomFeaturizer(allowable_sets)
# encoded_features = atom_featurizer.encode(atom)
class BondFeaturizer(Featurizer):
def __init__(self, allowable_sets):
super().__init__(allowable_sets)
# 增加一个维度来处理没有键的情况(例如,在一个原子的末端)
self.dim_no_bond = self.dim
self.dim += 1 # 额外的维度用于标识没有键
def encode(self, bond):
if bond is None:
# 如果键是 None,则返回一个特殊的编码
return np.zeros(self.dim) + [1.0]
output = np.zeros(self.dim)
# 先将没有键的维度设为0
output[-1] = 0.0
# 调用基类的 encode 方法,传入 bond 的一个属性或方法返回的信息
# 注意:这里可能需要一些调整,因为 bond 对象可能没有直接的方法可以调用
# 我们假设 bond 是一个有 bond_type 和 conjugated 属性的对象
bond_info = {
'bond_type': bond.GetBondType().name.lower(), 'conjugated': bond.GetIsConjugated()}
for name_feature, feature_value in bond_info.items():
if feature_value in self.features_mapping[name_feature