Essayez un modèle QSAR simple avec Chainer [Prédiction de la perméabilité de la barrière hémato-encéphalique des composés]

2020er mars 3

QSAR (Quantitative Structure-Activity Relationship) est une corrélation statistique entre la structure d'une substance chimique et son activité physiologique (toxicité, capacité à se lier aux enzymes, activité en tant que médicament, etc.).Les performances des composés peuvent être prédites à partir de corrélations basées sur de vastes ensembles de données expérimentales sur les produits chimiques.

Cette fois, nous allons créer un modèle QSAR simple qui "prédit la perméabilité de la barrière hémato-encéphalique d'un composé" à l'aide de Chainer, un cadre d'apprentissage en profondeur fabriqué au Japon, et vérifier ses performances par rapport à un ensemble de test.

Cible et données de prédiction

BBBP de Molecule Net est utilisé pour les données.Voir ci-dessous pour une vue d'ensemble des données.

En ce qui concerne la perméabilité de la barrière hémato-encéphalique du composé, «pénétration» vaut XNUMX et «non-pénétration» est XNUMX.

Créer un modèle

環境

from rdkit import rdBase
import chainer
print('rdkit version: ',rdBase.rdkitVersion)
chainer.print_runtime_info()
rdkit version: 2019.03.4 Plate-forme: Linux-5.0.0-37-generic-x86_64-with-debian-buster-sid Chainer: 6.2.0 NumPy: 1.17.4 CuPy: CuPy Version: 6.2.0 CUDA Root: / usr / local / cuda Version de build CUDA: 10010 Version du pilote CUDA: 10010 Version d'exécution CUDA: 10010 Version de build cuDNN: 7500 Version cuDNN: 7605 Version de build NCCL: 2402 Version d'exécution NCCL: 2402 iDeep: Non disponible

Vous pouvez vérifier la version de Chainer, Numpy, Cupy utilisée dans chainer.print_runtime_info ().

Construction de modèles

import numpy as np
import pandas as pd
from rdkit import Chem
from rdkit.Chem import Draw, PandasTools, Descriptors
 
# データの読み込み
df = pd.read_csv('BBBP.csv',index_col=0)
 
# smilesからmolファイルを生成し、データフレーム中に加える
PandasTools.AddMoleculeColumnToFrame(df, smilesCol = 'smiles')
 
# molができなかった行を削除する
df = df.dropna()
 
# molファイルから化合物記述子を算出する
for i,j in Descriptors.descList:
    df[i] = df['ROMol'].map(j)
df['Ipc'] = [Descriptors.Ipc(mol, avg=True) for mol in df['ROMol']]  
 
# chainer用にデータ型を変換
x = df.iloc[:,4:].values.astype('float32')
y = df['p_np'].values.astype('int32')
indices = np.array(range(x.shape[0])) # train_test_split後も列番号を保持しておく
 
# train, test, valに分割
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test, indices_train, indices_test = train_test_split(x, y, indices, test_size=0.05, random_state=123)
 
# 説明変数の標準化
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
scaler.fit(x_train)
x_train= scaler.transform(x_train)
x_test = scaler.transform(x_test)
 
print(type(x_train), x_train.shape, type(y_train), y_train.shape)
print(type(x_test), x_test.shape, type(y_test), y_test.shape)
(1937, 200) (1937,) (102, 200) (102,) 

Voir ici pour créer des descripteurs à partir d'objets mol.
Calculer les descripteurs moléculaires et les empreintes digitales de SMILES et les stocker dans un cadre de données [Python, RDKit]

Les tutoriels officiels sur l'utilisation de Chainer sont très complets.
Premiers pas avec le didacticiel Deep Learning Chainer

# 説明変数と目的変数のセットで使えるように変換する
from chainer.datasets import TupleDataset
train = TupleDataset(x_train, y_train)
test = TupleDataset(x_test, y_test)
 
# イテレータの準備
from chainer.iterators import SerialIterator
train_iter = SerialIterator(train, batch_size=64, repeat=True, shuffle=True)
test_iter = SerialIterator(test, batch_size=64, shuffle=False, repeat=False)
 
# ニューラルネットワークの作成
# 3層のmulti layer perceptron(MLP)
import chainer.links as L
import chainer.functions as F
from chainer import Chain
from chainer import optimizers, training
from chainer.training import extensions

class MLP(chainer.Chain):
 
    def __init__(self):
        super().__init__()
        with self.init_scope():
            self.fc1 = L.Linear(None, 100)
            self.fc2 = L.Linear(None, 20)
            self.fc3 = L.Linear(None, 2)
 
    def forward(self, x):
        h = F.relu(self.fc1(x))
        h = F.relu(self.fc2(h))
        h = self.fc3(h)
        return h
 
# ネットワークをClassifierでラップしする
# (目的関数(デフォルトはsoftmax交差エントロピー)の計算し、損失を返す)
predictor = MLP()
net = L.Classifier(predictor)
 
# 最適化手法を選択して、オプティマイザを作成する
optimizer = optimizers.MomentumSGD(lr=0.1).setup(net)
 
# アップデータにイテレータとオプティマイザを渡す
updater = training.StandardUpdater(train_iter, optimizer, device=-1)
trainer = training.Trainer(updater, (50, 'epoch'), out='/results/')
from chainer.training import extensions
 
trainer.extend(extensions.LogReport(trigger=(5, 'epoch'), log_name='log'))
trainer.extend(extensions.snapshot(filename='snapshot_epoch-{.updater.epoch}'))
trainer.extend(extensions.dump_graph('main/loss'))
trainer.extend(extensions.Evaluator(test_iter, net, device=-1), name='val')
trainer.extend(extensions.PrintReport(['epoch', 'iteration', 'main/loss', 'main/accuracy', 'val/main/loss', 'val/main/accuracy', 'fc1/W/data/mean', 'elapsed_time']))
trainer.extend(extensions.PlotReport(['fc1/W/grad/mean'], x_key='epoch', file_name='mean.png'))
trainer.extend(extensions.PlotReport(['main/loss', 'val/main/loss'], x_key='epoch', file_name='loss.png'))
trainer.extend(extensions.PlotReport(['main/accuracy', 'val/main/accuracy'], x_key='epoch', file_name='accuracy.png'))
trainer.extend(extensions.ParameterStatistics(net.predictor.fc1, {'mean': np.mean}, report_grads=True))
 
trainer.run()
from IPython.display import Image, display
display(Image(filename='results/accuracy.png'))

Il semble que la précision soit raisonnable, mais la précision de l'ensemble de test ne s'est pas beaucoup améliorée même au fur et à mesure que l'apprentissage progresse ...

inférence

# 学習したモデルで推論してみる
with chainer.using_config('train', False), chainer.using_config('enable_backprop', False):
    y_pred = predictor(x_test)
 
# 推論結果の確認
print('accuracy', F.accuracy(y_pred, y_test)) # accuracy variable(0.88235295)
 
from sklearn.metrics import confusion_matrix
confusion_matrix(y_test, y_pred.data.argmax(axis=1))
 tableau ([[21, 7], [5, 69]]) 

la précision est une valeur comme vous pouvez le voir sur la figure.Lors de l'évaluation de l'exactitude de la classification par la matrice de confusion, il y a des faux positifs et des faux négatifs, mais il semble que la précision ne soit pas acquise par la classification biaisée d'un côté.

# 一部予測結果を見てみる
for i in range(int(len(y_pred)/10)):
    print('No.', indices_test[i])
    print('label:', y_test[i])
    print('pred :', np.argmax(y_pred[i].array))
    img = Draw.MolToImage(df.ROMol[indices_test[i]])
    display(img)

L'image fait partie de la sortie, mais la réponse correcte est qu'elle peut être discernée par l'œil humain.Cela semble amusant de scruter ce que vous avez fait une erreur.