DeepChem教程 6:图卷积

DeepChem教程 6:图卷积

本教程我们学习更多的图卷积。处理分子数据有一个最为强大的深度学习工具。原因是分子可以很自然的看作图。注意,这类的标准的化学图形我们从高中就开始用于可视化分子作为图。在本教程的后一部分,我们将更详细的探求这种关系。我们将更深入的理解这些系统是如何工作的。

什么是图卷积?

考虑一下一种常用于处理图像的标准的卷积神经网络。每个像素有一个矢量数值,如红、绿、蓝通道值。数据传递给一系列的卷积层。每一层组合数据自像素及它的邻居以产生新的像素的矢量数据。早期的层检测局部的模式,后期的层检测更大的更抽象的模式。通常卷积层随池化层改变,池化层进行一些局部区域的最大最小化之类的操作。

图卷积相似,但是它们对图操作。它们从图上的节点的矢量数据开始(如,节点代表的原子的化学特征)。卷积和池化层组合信息自相连的节点(如,相结合的原子)以为每个节点产生新的数据矢量。

训练GraphConvModel

让我们来使用MoleculeNet加载Tox21数据集。为了特征化数据以便图卷积神经网络使用,我们设置特征化器选项为'GraphConv'MoleculeNet的调用返回训练集、验证集、测试集供我们使用。它也返回tasks,即任务名的列表,也返回transformers,数据转换器的列表,用于处理数据集。(通常大部分深度网络都是挑剔的,需要一系列的数据转换过程以保证训练过程的稳定性。)

In [1]:

import deepchem as dc

tasks, datasets, transformers = dc.molnet.load_tox21(featurizer='GraphConv')

train_dataset, valid_dataset, test_dataset = datasets

现在我们用这个数据集来训练图卷积网络。DeepChem有一个GraphConvModel类打包标准的图卷积结构方便用户使用。我们来实例化类的对象并用我们的数据集来训练。

In [2]:

n_tasks = len(tasks)

model = dc.models.GraphConvModel(n_tasks, mode='classification')

model.fit(train_dataset, nb_epoch=50)

Out[2]:

0.28185401916503905

我们来评估一下我们训练的模型的性能。对于这个,我们需要确定一个度量来衡量模型的性能。dc.metrics 已经存贮了一系列的量度。对于这个数据集,使用ROC-AUC是标准,即接受者操作特征曲线下的面积(它测量了精确度和召回之间接妥协)。幸运的是,DeepChem已有ROC-AUC分可用。为了测量模型在这个量度下的性能,我们使用便利的函数 model.evaluate()

In [3]:

metric = dc.metrics.Metric(dc.metrics.roc_auc_score)

print('Training set score:', model.evaluate(train_dataset, [metric], transformers))

print('Test set score:', model.evaluate(test_dataset, [metric], transformers))

Training set score: {'roc_auc_score': 0.96959686893055}

Test set score: {'roc_auc_score': 0.795793783300876}

结果很好,GraphConvModel非常易于使用。但是这到底发生了什么呢?我们可以自已构建GraphConvModel吗?当然!DeepChem提供了Keras层进行图卷积计算。我们打算使用DeepChem的如下层。

  • GraphConv: 这个层实施图卷积。图卷积以非线性的形式组合每个节点及其相邻节点的特征。这混合了图局部邻区域的信息。
  • GraphPool: 这一层最大化相邻原子的特征向量。你可以认为这一层是2D卷积的max-pooling层只是它对图操作。
  • GraphGather: 许多的图卷积网络按图-节操作特征向量。拿个分子来举例,每个节点代表原子,网络可以操作汇总局总原子化学性质的原子的特征向量。但是,应用的最后,我们很可能处理分子水平的特征表示。这一层产生图水平的特征向量,通过组合所有节点水平的特征向量。

除此之外,我们要应用标准的神经网络层如 DenseBatchNormalizationSoftmax层。

In [4]:

from deepchem.models.layers import GraphConv, GraphPool, GraphGather

import tensorflow as tf

import tensorflow.keras.layers as layers

batch_size = 100

class MyGraphConvModel(tf.keras.Model):

  def __init__(self):

    super(MyGraphConvModel, self).__init__()

    self.gc1 = GraphConv(128, activation_fn=tf.nn.tanh)

    self.batch_norm1 = layers.BatchNormalization()

    self.gp1 = GraphPool()

    self.gc2 = GraphConv(128, activation_fn=tf.nn.tanh)

    self.batch_norm2 = layers.BatchNormalization()

    self.gp2 = GraphPool()

    self.dense1 = layers.Dense(256, activation=tf.nn.tanh)

    self.batch_norm3 = layers.BatchNormalization()

    self.readout = GraphGather(batch_size=batch_size, activation_fn=tf.nn.tanh)

    self.dense2 = layers.Dense(n_tasks*2)

    self.logits = layers.Reshape((n_tasks, 2))

    self.softmax = layers.Softmax()

  def call(self, inputs):

    gc1_output = self.gc1(inputs)

    batch_norm1_output = self.batch_norm1(gc1_output)

    gp1_output = self.gp1([batch_norm1_output] + inputs[1:])

    gc2_output = self.gc2([gp1_output] + inputs[1:])

    batch_norm2_output = self.batch_norm1(gc2_output)

    gp2_output = self.gp2([batch_norm2_output] + inputs[1:])

dense1_output = self.dense1(gp2_output)

    batch_norm3_output = self.batch_norm3(dense1_output)

    readout_output = self.readout([batch_norm3_output] + inputs[1:])

    logits_output = self.logits(self.dense2(readout_output))

return self.softmax(logits_output)

现在我们可以更清楚的看到发生了什么。有两个卷积块,每个都由GraphConv组成,接下来是batch normalization,接下来是GraphPool进行最大池化。最后是全链接层,另一个batch normalization,一个GraphGather组合所有不同的节点的数据,最后一个全链接层产生全局输出。

我们来创建DeepChem模型,它打包我们刚才产生的Keras模型。我们也指定损失函数使模型知道最小化的目标。    

In [5]:

model = dc.models.KerasModel(MyGraphConvModel(), loss=dc.models.losses.CategoricalCrossEntropy())

这个模型的输出是什么?一个图卷积需要每个分子的完整的描述,包括节点列表,并描述节点的相互键合。事实上,如果我们检查数据集我们发现特征数组包ConvMol类型的Python对像。

In [6]:

test_dataset.X[0]

Out[6]:

<deepchem.feat.mol_graphs.ConvMol at 0x14d0b1650>

模型的期望输入为数值数组,而不是Python对象。我们必须转换ConvMolGraphConvGraphPool, GraphGather层期望的特殊的数组。幸运的是,ConvMol类包括了进行这种操作的代码,以及组合所有的分子到一个批以产生一个数组集。

    下面的代码创建Python生成器以批量的产生输入、标签、权重数据,它们都是Numpy数组。 atom_features为每个原子存贮长度为75的特征向量。其它的输入需要支持TensorFlowminibatching degree_slice 是索引,便于一定水平上定位分子中的原子。Membership确定分子中的原子的关系(原子i属于分子 membership[i])。

deg_adjs 是个包含原子水平分类的相邻性的列表的列表。更多的细节请见代码code.

In [7]:

from deepchem.metrics import to_one_hot

from deepchem.feat.mol_graphs import ConvMol

import numpy as np

def data_generator(dataset, epochs=1):

  for ind, (X_b, y_b, w_b, ids_b) in enumerate(dataset.iterbatches(batch_size, epochs,deterministic=False, pad_batches=True)):

    multiConvMol = ConvMol.agglomerate_mols(X_b)

    inputs = [multiConvMol.get_atom_features(), multiConvMol.deg_slice, np.array(multiConvMol.membership)]

    for i in range(1, len(multiConvMol.get_deg_adjacency_lists())):

      inputs.append(multiConvMol.get_deg_adjacency_lists()[i])

    labels = [to_one_hot(y_b.flatten(), 2).reshape(-1, n_tasks, 2)]

    weights = [w_b]

yield (inputs, labels, weights)

我们现在可以用fit_generator(generator)来训练模型,它将使用我们用来训练模型的生成器。

In [8]:

model.fit_generator(data_generator(train_dataset, epochs=50))

Out[8]:

0.21941944122314452

现在我们已经训练了我们的图卷积方法,我们来评估一下性能。我们还要再一次使用定义的生成器来评估模型的性能。

In [9]:

print('Training set score:', model.evaluate_generator(data_generator(train_dataset), [metric], transformers))

print('Test set score:', model.evaluate_generator(data_generator(test_dataset), [metric], transformers))

Training set score: {'roc_auc_score': 0.8425638289185731}

Test set score: {'roc_auc_score': 0.7378436684114341}

成功了!我们构建的模型的表现与GraphConvModel几乎相同。如果你想要构建你自已的模型,你可以按照我们前面的例子去做。我们希望看到令人兴奋的结果。

下载全文请到www.data-vision.net,技术联系电话13712566524

猜你喜欢

转载自blog.csdn.net/lishaoan77/article/details/114295314
今日推荐