Chainer: クラス分類による溶解度の予測

By | 2015年7月17日


今回は、Deep Learningの新しいフレームワークであるChainerを使って、クラス分類による溶解度の予測を行いたいと思います。

Chainer 公式サイト

業務では主にPythonを使うことが多いので、Chainerは、本当に有難いフレームワークだと思っています。

インストール

インストールは本当に簡単です!

> pip install chainer

クラス分類による溶解度の予測

Chainerのサンプルプログラムにあるtrain_mnist.pyを参考にして、以下のプログラムを書いてみました。

chainer_01.py:

from rdkit import Chem
from rdkit.Chem import AllChem
from rdkit.Chem import Descriptors
from rdkit import DataStructs
from rdkit.ML.Descriptors import MoleculeDescriptors
from rdkit import rdBase
print 'RDKit version ',rdBase.rdkitVersion

import chainer
from chainer import computational_graph as c
import chainer.functions as F
from chainer import cuda
from chainer import optimizers
print 'Chainer version ',chainer.__version__

import six
import numpy as np
import sys

from sklearn.preprocessing import MinMaxScaler
from sklearn import metrics

# 記述子の準備
act_classes={'(A) low':0,'(B) medium':1,'(C) high':2}
descList = [x[0] for x in Descriptors._descList]
calc = MoleculeDescriptors.MolecularDescriptorCalculator(descList)

# 訓練データの読み込み
# 訓練データの読み込み
# データセットは、以下のサイトにある化合物のlogS値(Huuskonen dataset)を利用しました。
# 入手先:http://sourceforge.net/p/rdkit/code/HEAD/tree/trunk/Docs/Book/data/
# ファイル名: solubility.train.sdf, solubility.test.sdf
#  solubility.train.sdfに含まれるCyhexatinは、一部の記述子が計算できなかったので、除外しています。
m_train = [m for m in Chem.SDMolSupplier('solubility.train.sdf') if m is not None]
x_train = [calc.CalcDescriptors(m) for m in m_train]
x_train = np.array(x_train,dtype=np.float32)
y_train = [act_classes[m.GetProp('SOL_classification')] for m in m_train]
y_train = np.array(y_train,dtype=np.int32)

# テストデータの読み込み
m_test = [m for m in Chem.SDMolSupplier('solubility.test.sdf') if m is not None]
x_test = [calc.CalcDescriptors(m) for m in m_test]
x_test = np.array(x_test,dtype=np.float32)
y_test = [act_classes[m.GetProp('SOL_classification')] for m in m_test]
y_test = np.array(y_test,dtype=np.int32)

# 訓練データ、テストデータのスケーリング
scaler = MinMaxScaler()
scaler.fit(x_train)
x_train = scaler.transform(x_train)
x_test  = scaler.transform(x_test)

# パラメータ設定
batchsize = 100         # 確率的勾配降下法で学習させるバッチサイズ
n_epoch = 30            # 学習の繰り返し回数
n_units = 1000          # 中間層のユニット数
Ndesc = len(descList)   # 入力層のユニット数(記述子の数)
Nout = 3                # 出力層のユニット数(クラス数)
N = y_train.size        # 訓練データ数
N_test = y_test.size    # テストデータ数


# Prepare multi-layer perceptron model
# 入力:記述子の数(196) 出力:クラスの数(3)
model = chainer.FunctionSet(l1=F.Linear(Ndesc, n_units),
                            l2=F.Linear(n_units, n_units),
                            l3=F.Linear(n_units, Nout))

# Neural net architecture
def forward(x_data, y_data, train=True):
    x, t = chainer.Variable(x_data), chainer.Variable(y_data)
    h1 = F.dropout(F.relu(model.l1(x)),  train=train)
    h2 = F.dropout(F.relu(model.l2(h1)), train=train)
    y = model.l3(h2)
    return F.softmax_cross_entropy(y, t), F.accuracy(y, t)

# Setup optimizer
optimizer = optimizers.Adam()
optimizer.setup(model.collect_parameters())

# Learning loop
for epoch in six.moves.range(1, n_epoch + 1):

    perm = np.random.permutation(N)
    sum_accuracy = 0
    sum_loss = 0

    for i in six.moves.range(0, N, batchsize):
        x_batch = x_train[perm[i:i + batchsize]]
        y_batch = y_train[perm[i:i + batchsize]]
        optimizer.zero_grads()
        loss, acc = forward(x_batch, y_batch)
        loss.backward()
        optimizer.update()
        sum_loss += float(cuda.to_cpu(loss.data)) * len(y_batch)
        sum_accuracy += float(cuda.to_cpu(acc.data)) * len(y_batch)

    print('epoch={}, train mean loss={}, accuracy={}'.format(
        epoch, sum_loss / N, sum_accuracy / N))

# テストデータのクラス予測
x, t = chainer.Variable(x_test), chainer.Variable(y_test)
h1 = F.relu(model.l1(x))
h2 = F.relu(model.l2(h1))
y = model.l3(h2)
loss = F.softmax_cross_entropy(y, t)
acc = F.accuracy(y, t)
print('test  mean loss={}, accuracy={}'.format(loss.data, acc.data))

# テストデータの評価 (Confusion matrixの計算)
prob = F.softmax(y).data
pred_y = []
for p,y in zip(prob,y_test):
    pre_y= np.argmax(p)
    #print pre_y,y
    pred_y.append(pre_y)
pred_y = np.array(pred_y)
confmat = metrics.confusion_matrix(y_test,pred_y)
print confmat

実行結果

RDKit version  2014.09.2
Chainer version  1.1.0
epoch=1, train mean loss=0.894346793881, accuracy=0.566406252095
epoch=2, train mean loss=0.645627270918, accuracy=0.691406251863
epoch=3, train mean loss=0.513133924454, accuracy=0.779296863126
epoch=4, train mean loss=0.435840750113, accuracy=0.811523431214
epoch=5, train mean loss=0.393394864397, accuracy=0.818359375233
epoch=6, train mean loss=0.388552646618, accuracy=0.832031250233
epoch=7, train mean loss=0.358083432424, accuracy=0.838867195882
epoch=8, train mean loss=0.352884827647, accuracy=0.847656235332
epoch=9, train mean loss=0.383986310917, accuracy=0.833984377794
epoch=10, train mean loss=0.343003616203, accuracy=0.851562500466
epoch=11, train mean loss=0.302874319255, accuracy=0.869140624767
epoch=12, train mean loss=0.268378470792, accuracy=0.883789068786
epoch=13, train mean loss=0.273156624346, accuracy=0.885742178652
epoch=14, train mean loss=0.250554838101, accuracy=0.889648437966
epoch=15, train mean loss=0.256678346079, accuracy=0.898437502328
epoch=16, train mean loss=0.220834126638, accuracy=0.916015628027
epoch=17, train mean loss=0.255951596599, accuracy=0.88769530924
epoch=18, train mean loss=0.212121372344, accuracy=0.914062497672
epoch=19, train mean loss=0.222044002789, accuracy=0.905273431912
epoch=20, train mean loss=0.234405800642, accuracy=0.905273449374
epoch=21, train mean loss=0.234147735522, accuracy=0.902343754424
epoch=22, train mean loss=0.206508405623, accuracy=0.91796874674
epoch=23, train mean loss=0.201678971905, accuracy=0.914062494645
epoch=24, train mean loss=0.180077250669, accuracy=0.92773438571
epoch=25, train mean loss=0.168802947854, accuracy=0.935546882683
epoch=26, train mean loss=0.167988513713, accuracy=0.931640626164
epoch=27, train mean loss=0.146641206753, accuracy=0.939453131985
epoch=28, train mean loss=0.162885584054, accuracy=0.931640614523
epoch=29, train mean loss=0.150213876128, accuracy=0.943359381054
epoch=30, train mean loss=0.142516513588, accuracy=0.941406241851
test  mean loss=0.423470169306, accuracy=0.859922170639
[[90 12  0]
 [12 96  7]
 [ 0  5 35]]

過去の記事と比較しても、非常に良好な結果だと思います。

利用したソフトウェア:
Chainer 1.1.0
RDKit_2014_09_2