Попробуйте простую модель QSAR с помощью Chainer [Прогнозирование проницаемости соединений через гематоэнцефалический барьер]

2020 год 3 месяц 2 день

QSAR (количественное соотношение структура-активность) - это статистическая корреляция между структурой химического вещества и его физиологической активностью (токсичность, способность связываться с ферментами, активность как лекарство и т. Д.).Характеристики соединения можно предсказать на основе корреляций, основанных на обширных наборах экспериментальных данных по химическим веществам.

На этот раз мы создадим простую модель QSAR, которая «прогнозирует проницаемость соединений через гематоэнцефалический барьер», используя Chainer, платформу глубокого обучения, сделанную в Японии, и проверим ее производительность по набору тестов.

Цель прогноза и данные

Для данных используется BBBP Molecule Net.Ниже приведены данные с высоты птичьего полета.

Что касается проницаемости соединения через гематоэнцефалический барьер, «проникновение» равно XNUMX, а «непроникновение» равно XNUMX.

Создание модели

環境

from rdkit import rdBase
import chainer
print('rdkit version: ',rdBase.rdkitVersion)
chainer.print_runtime_info()
Версия rdkit: 2019.03.4 Платформа: Linux-5.0.0-37-generic-x86_64-with-debian-buster-sid Chainer: 6.2.0 NumPy: 1.17.4 CuPy: CuPy Версия: 6.2.0 Корень CUDA: / usr / local / cuda Версия сборки CUDA: 10010 Версия драйвера CUDA: 10010 Версия среды выполнения CUDA: 10010 Версия сборки cuDNN: 7500 Версия сборки cuDNN: 7605 Версия сборки NCCL: 2402 Версия среды выполнения NCCL: 2402 iDeep: недоступно

Вы можете проверить версию Chainer, Numpy, Cupy, используемую в chainer.print_runtime_info ().

Построение модели

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,) 

См. Здесь для создания дескрипторов из объектов mol.
Вычислить молекулярные дескрипторы и отпечатки пальцев из SMILES и сохранить их во фрейме данных [Python, RDKit]

Официальные руководства по использованию Chainer очень обширны.
Начало работы с учебником 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'))

Кажется, что точность разумная, но точность набора тестов не сильно улучшилась даже по мере того, как обучение продолжается ...

вывод

# 学習したモデルで推論してみる
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))
 массив ([[21, 7], [5, 69]]) 

Как видно из рисунка, точность - это величина.При оценке точности классификации по матрице неточностей есть ложные срабатывания и ложные отрицания, но кажется, что точность не достигается за счет смещения классификации в одну сторону.

# 一部予測結果を見てみる
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)

Изображение является частью вывода, но правильный ответ состоит в том, что его можно различить человеческим глазом.Кажется забавным разобраться, в чем вы допустили ошибку.