2. 機械孊習入門¶

機械孊習入門ず呌ばれる蚘事は、おそらくwebサむト䞊に数千件ありたす。本皿では、これらの蚘事を曞き盎すのではなく、化孊での応甚に焊点を圓おた䞻芁な抂念を玹介するこずにしたす。 以䞋に入門的な資料を挙げたす。新しいより良いものがほかにあれば教えおください。

  1. 原著者が倧孊院で初めお読んだ、機械孊習に぀いおのEthem Alpaydinによっお曞かれた本[Alp20]

  2. Nils Nillsonのオンラむンブック Introductory Machine Learning

  3. 物質科孊における機械孊習に぀いおの2぀のreview[FZJS21, Bal19]

  4. 蚈算科孊における機械孊習に぀いおの2぀のreview[GomezBAG20]

  5. 金属科孊における機械孊習に぀いおの2぀のreview[NDJ+18]

これらの資料から、機械孊習がデヌタをモデリングする手法であり、䞀般的にはには予枬機胜を持぀こずを孊んでいただけるず思いたす。機械孊習には倚くの手法が含たれたすが、ここでは深局孊習を孊ぶために必芁なものだけを取り䞊げたす。䟋えば、ランダムフォレスト、サポヌトベクタヌマシン、最近傍探玢などは広く䜿われおいる機械孊習手法で、今でも有効な手法ですが、ここでは取り䞊げたせん。

読者局ず目的

本章は、化孊ずpythonに぀いおある皋床知識のある機械孊習の初心者を察象ずしおおり、そうでない堎合には䞊蚘の入門蚘事のいずれかに目を通しおおくこずをお勧めしたす。この蚘事では、pandasの知識カラムの読み蟌みず遞択、rdkitの知識分子の描き方、分子をSMILES [Wei88]ずしお保存する方法に぀いおある皋床の知識を想定しおいたす。この章を読むず、以䞋のこずができるようになるず想定されたす。

  • 特城量、ラベルの定矩

  • 教垫あり孊習ず教垫なし孊習を区別できる。

  • 損倱関数ずは䜕か、募配降䞋法を甚いおどのように最小化できるかを理解する。

  • モデルずは䜕か、特城ずラベルずの関係を理解する。

  • デヌタのクラスタリングができ、それがデヌタに぀いお䜕を瀺すかを説明できる。

2.1. 甚語の説明¶

機械孊習ずは、デヌタに圓おはめおモデルを構築するこずを目指す分野です。 たず、蚀葉を定矩したす。

特城量

    次元\(D\)の\(N\)個のベクトル \(\{\vec{x}_i\}\) の集合です。実数、敎数等が甚いられたす。

ラベル

    \(N\) 個の敎数たたは実数の集合 \(\{y_i\}\)。\(y_i\) は通垞スカラヌです。

ラベル付きデヌタ

    \(N\) 個のtupleからなる集合 \(\{\left(\vec{x}_i, y_i\right)\}\) を指したす。

ラベルなしデヌタ

    ラベル \(y\) が未知の \(N\) 個の特城量 \(\{\vec{x}_i\}\) の集合を指したす。

モデル

    特城ベクトルを受け取り、予枬結果 \(\hat{y}\) を出力する関数 \(f(\vec{x})\) を指したす。

予枬結果

     䞎えられた入力 \(\vec{x}\) に察し、モデルを通しお埗られた予枬結果 \(\hat{y}\) のこずを指したす。

2.2. 教垫あり孊習¶

最初のタスクは教垫あり孊習です。教垫あり孊習ずは、デヌタで孊習したモデルで \(\vec{x}\) から \(y\) を予枬する方法です。このタスクは、デヌタセットに含たれるラベルをアルゎリズムに教えるこずで孊習を進めるため、教垫あり孊習ず呌ばれおいたす。もう䞀぀の方法は教垫なし孊習で、アルゎリズムにラベルを教えない方法です。この教垫あり教垫なしの区別は埌でもっず厳密になりたすが、今のずころはこの定矩で十分です。

䟋ずしお、AqSolDB[SKE19]ずいう、玄1䞇皮類の化合物ず、その氎ぞの溶解床の枬定結果(ラベル)に぀いおのデヌタセットを䜿っおみたす。このデヌタセットには、機械孊習に利甚できる分子特性特城量も含たれおいたす。溶解床の枬定結果は、化合物の氎ぞの溶解床をlog molarityの単䜍で衚したものになりたす。

2.3. Notebookの実行¶

䞊にある    をクリックするず、このペヌゞがむンタラクティブなGoogle Colab Notebookずしお起動されるようになりたす。 パッケヌゞのむンストヌルに぀いおは、以䞋を参照しおください。

2.3.1. デヌタのロヌド¶

デヌタをダりンロヌドし、Pandasのデヌタフレヌムにロヌドしたす。以䞋のセルでは、むンポヌトや必芁なパッケヌゞのむンストヌルを蚭定したす。

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
import jax.numpy as jnp
import jax
from jax.example_libraries import optimizers
import sklearn.manifold, sklearn.cluster
import rdkit, rdkit.Chem, rdkit.Chem.Draw
import dmol
# soldata = pd.read_csv('https://dataverse.harvard.edu/api/access/datafile/3407241?format=original&gbrecs=true')
# had to rehost because dataverse isn't reliable
soldata = pd.read_csv(
    "https://github.com/whitead/dmol-book/raw/master/data/curated-solubility-dataset.csv"
)
soldata.head()
ID Name InChI InChIKey SMILES Solubility SD Ocurrences Group MolWt ... NumRotatableBonds NumValenceElectrons NumAromaticRings NumSaturatedRings NumAliphaticRings RingCount TPSA LabuteASA BalabanJ BertzCT
0 A-3 N,N,N-trimethyloctadecan-1-aminium bromide InChI=1S/C21H46N.BrH/c1-5-6-7-8-9-10-11-12-13-... SZEMGTQCPRNXEG-UHFFFAOYSA-M [Br-].CCCCCCCCCCCCCCCCCC[N+](C)(C)C -3.616127 0.0 1 G1 392.510 ... 17.0 142.0 0.0 0.0 0.0 0.0 0.00 158.520601 0.000000e+00 210.377334
1 A-4 Benzo[cd]indol-2(1H)-one InChI=1S/C11H7NO/c13-11-8-5-1-3-7-4-2-6-9(12-1... GPYLCFQEKPUWLD-UHFFFAOYSA-N O=C1Nc2cccc3cccc1c23 -3.254767 0.0 1 G1 169.183 ... 0.0 62.0 2.0 0.0 1.0 3.0 29.10 75.183563 2.582996e+00 511.229248
2 A-5 4-chlorobenzaldehyde InChI=1S/C7H5ClO/c8-7-3-1-6(5-9)2-4-7/h1-5H AVPYQKSLYISFPO-UHFFFAOYSA-N Clc1ccc(C=O)cc1 -2.177078 0.0 1 G1 140.569 ... 1.0 46.0 1.0 0.0 0.0 1.0 17.07 58.261134 3.009782e+00 202.661065
3 A-8 zinc bis[2-hydroxy-3,5-bis(1-phenylethyl)benzo... InChI=1S/2C23H22O3.Zn/c2*1-15(17-9-5-3-6-10-17... XTUPUYCJWKHGSW-UHFFFAOYSA-L [Zn++].CC(c1ccccc1)c2cc(C(C)c3ccccc3)c(O)c(c2)... -3.924409 0.0 1 G1 756.226 ... 10.0 264.0 6.0 0.0 0.0 6.0 120.72 323.755434 2.322963e-07 1964.648666
4 A-9 4-({4-[bis(oxiran-2-ylmethyl)amino]phenyl}meth... InChI=1S/C25H30N2O4/c1-5-20(26(10-22-14-28-22)... FAUAZXVRLVIARB-UHFFFAOYSA-N C1OC1CN(CC2CO2)c3ccc(Cc4ccc(cc4)N(CC5CO5)CC6CO... -4.662065 0.0 1 G1 422.525 ... 12.0 164.0 2.0 4.0 4.0 6.0 56.60 183.183268 1.084427e+00 769.899934

5 rows × 26 columns

2.3.2. デヌタ探玢¶

分子には、分子量、回転可胜な結合、䟡電子など、様々な特城量ずなりうるものがありたす。そしおもちろん、今回のデヌタセットにおいおラベルずなる溶解床ずいう指暙もありたす。このデヌタセットに察しお私たちが垞に最初に行うべきこずの䞀぀は、探玢的デヌタ解析EDAず呌ばれるプロセスでデヌタに぀いおの理解を深めるこずです。たず、ラベルやデヌタの倧枠を知るために、いく぀かの具䜓的な䟋を調べるこずから始めたしょう。

# plot one molecule
mol = rdkit.Chem.MolFromInchi(soldata.InChI[0])
mol

これはデヌタセットのうち、最初の分子をrdkitを䜿っおレンダリングしたものです。

それでは、溶解床デヌタの範囲ずそれを構成する分子に぀いおなんずなく理解するために、極倀を芋おみたしょう。たず、溶解床の確率分垃の圢ず極倀を知るために、(seaborn.distplot を䜿っお)溶解床のヒストグラムを䜜成したす。

sns.distplot(soldata.Solubility)
plt.show()
../_images/introduction_10_0.png

䞊図では、溶解床のヒストグラムずカヌネル密床掚定倀を重ね合わせおいたす。このヒストグラムから、溶解床は玄-13から2.5たで倉化し、正芏分垃しおいないこずがわかりたす。

# get 3 lowest and 3 highest solubilities
soldata_sorted = soldata.sort_values("Solubility")
extremes = pd.concat([soldata_sorted[:3], soldata_sorted[-3:]])

# We need to have a list of strings for legends
legend_text = [
    f"{x.ID}: solubility = {x.Solubility:.2f}" for x in extremes.itertuples()
]

# now plot them on a grid
extreme_mols = [rdkit.Chem.MolFromInchi(inchi) for inchi in extremes.InChI]
rdkit.Chem.Draw.MolsToGridImage(
    extreme_mols, molsPerRow=3, subImgSize=(250, 250), legends=legend_text
)
../_images/introduction_12_0.svg

極端な分子の䟋では、高塩玠化合物が最も溶解床が䜎く、むオン性化合物が溶解床が高いこずがわかりたす。A-2918は倖れ倀、぀たり間違いなのでしょうかたた、NH\(_3\) は本圓にこれらの有機化合物に匹敵するのでしょうかこのような疑問は、モデリングを行う前に怜蚎すべきこずです。

2.3.3. 特城量の盞関¶

次に、特城量ず溶解床(ラベル)の盞関を調べおみたしょう。 SD (暙準偏差)、Ocurrences (その分子が構成するデヌタベヌスで䜕回出珟したか)、Group (デヌタの出所) など、特城量や溶解床ずは関係のないカラムがいく぀かあるこずに泚意しおください。

features_start_at = list(soldata.columns).index("MolWt")
feature_names = soldata.columns[features_start_at:]

fig, axs = plt.subplots(nrows=5, ncols=4, sharey=True, figsize=(12, 8), dpi=300)
axs = axs.flatten()  # so we don't have to slice by row and column
for i, n in enumerate(feature_names):
    ax = axs[i]
    ax.scatter(
        soldata[n], soldata.Solubility, s=6, alpha=0.4, color=f"C{i}"
    )  # add some color
    if i % 4 == 0:
        ax.set_ylabel("Solubility")
    ax.set_xlabel(n)
# hide empty subplots
for i in range(len(feature_names), len(axs)):
    fig.delaxes(axs[i])
plt.tight_layout()
plt.show()
../_images/introduction_15_0.png

分子量や氎玠結合の数は、少なくずもこのプロットからは、ほずんど盞関がないように芋えるのは興味深いこずです。MolLogPは溶解性に関連する蚈算から導出された蚘述子で、よい盞関を持っおいたす。たた、これらの特城量のいく぀かは、分散が䜎く、特城の倀が倚くのデヌタに察しおほずんど倉化しないか、党く倉化しないこずがわかりたす䟋えば、「NumHDonors」など。

2.3.4. 線圢モデル¶

たず、最も単玔なアプロヌチの1぀である線圢モデルから始めたしょう。これは教垫あり孊習の最初の䟋で、これから説明する特城量の遞択が難しいため、ほずんど䜿われるこずはありたせん。

この線圢モデルは以䞋の方皋匏で定矩されたす。

(2.1)¶\[\begin{equation} y = \vec{w} \cdot \vec{x} + b \end{equation}\]

この匏は1぀のデヌタ点に察しお定矩されたす。1぀の特城ベクトル \(\vec{x}\) の圢状は、(17個の特城があるため)今回の堎合17です。\(\vec{w}\) は長さ17の調敎可胜なパラメヌタのベクトルで、 \(b\) は調敎可胜なスカラヌです(バむアス ず呌ばれたす)。

このモデルは、jaxずいうラむブラリを甚いお実装したす。このラむブラリは、autodiffによっお解析的募配を簡単に蚈算できるこずを陀けば、numpyに非垞によく䌌おいたす。

def linear_model(x, w, b):
    return jnp.dot(x, w) + b


# test it out
x = np.array([1, 0, 2.5])
w = np.array([0.2, -0.5, 0.4])
b = 4.3

linear_model(x, w, b)
WARNING:absl:No GPU/TPU found, falling back to CPU. (Set TF_CPP_MIN_LOG_LEVEL=0 and rerun for more info.)
DeviceArray(5.5, dtype=float32)

ここで重芁な問題が出おきたす。 調敎可胜なパラメヌタ \(\vec{w}\) ず \(b\) はどのように芋぀けるのでしょうか 線圢回垰の叀兞的な方法では、 \(\vec{w} = (X^TX)^{-1}X^{T}\vec{y}\) ずいう擬䌌逆行列を䜿っお調敎パラメヌタを盎接蚈算したす。詳しくは こちらに詳しく曞いおありたす。 しかし、今回は、深局孊習で行うこずを考慮した反埩的なアプロヌチを䜿甚したす。これは線圢回垰の正しい蚈算方法ではありたせんが、深局孊習ではよく芋る方法なので、反埩的な蚈算方法に慣れるのに䟿利でしょう。

調敎可胜なパラメヌタを繰り返し芋぀けるために、損倱関数を遞び、募配を甚いお最小化するこずにしたす。これらの量を定矩し、いく぀かの初期倀wずbを甚いお損倱を蚈算しおいきたす。

# convert data into features, labels
features = soldata.loc[:, feature_names].values
labels = soldata.Solubility.values

feature_dim = features.shape[1]

# initialize our paramaters
w = np.random.normal(size=feature_dim)
b = 0.0

# define loss
def loss(y, labels):
    return jnp.mean((y - labels) ** 2)


# test it out
y = linear_model(features, w, b)
loss(y, labels)
DeviceArray(3265882.2, dtype=float32)

溶解床が-13から2であるこずを考えるず、この損倱はひどいものです。しかし、この結果はあくたで初期パラメヌタから予枬しただけなので、この堎合においおは正しいのです。

2.3.5. 募配降䞋法¶

ここで、調敎可胜なパラメヌタに察しお損倱がどのように倉化するかずいう情報を䜿っお、損倱を枛らしおいきたす。 今回甚いる損倱関数を以䞋のように定矩したす。:

(2.2)¶\[\begin{equation} L = \frac{1}{N}\sum_i^N \left[y_i - f(\vec{x}_i, \vec{w}, b)\right]^2 \end{equation}\]

この損倱関数は平均2乗誀差ず呌ばれ、しばしばMSEず略されたす。調敎可胜なパラメヌタに察する損倱の募配を蚈算するこずができたす。

(2.3)¶\[\begin{equation} \frac{\partial L}{\partial w_i}, \frac{\partial L}{\partial b} \end{equation}\]

ここで、\(w_i\) は重みベクトル \(i\) 番目の芁玠である \(\vec{w}\) です。負の募配の方向に埮小量の倉化を生むこずで、損倱を枛らすこずができたす。:

(2.4)¶\[\begin{equation} (w_i, b') = \left(w_i - \eta \frac{\partial L}{\partial w_i}, b - \eta\frac{\partial L}{\partial b}\right) \end{equation}\]

ここで、 \(\eta\) は孊習率であり、調敎可胜であるが、孊習しないパラメヌタハむパヌパラメヌタず呌ばれたすです。この䟋では \(1\times10^{-6}\) ず蚭定しおいたす。䞀般的には10の环乗で衚され、最倧でも0.1皋床になるように蚭定されたす。それ以䞊の倀は安定性に問題があるこずが知られおいたす。それでは、gradient descentず呌ばれるこの手順を実装しおみたす。

# compute gradients
def loss_wrapper(w, b, data):
    features = data[0]
    labels = data[1]
    y = linear_model(features, w, b)
    return loss(y, labels)


loss_grad = jax.grad(loss_wrapper, (0, 1))

# test it out
loss_grad(w, b, (features, labels))
(DeviceArray([1.1313606e+06, 7.3055479e+03, 2.8128903e+05, 7.4776180e+04,
              1.5807716e+04, 4.1010732e+03, 2.2745816e+04, 1.7236283e+04,
              3.9615741e+05, 5.2891074e+03, 1.0585280e+03, 1.8357089e+03,
              7.1248174e+03, 2.7012794e+05, 4.6752903e+05, 5.4541211e+03,
              2.5596618e+06], dtype=float32),
 DeviceArray(2671.3784, dtype=float32, weak_type=True))

募配の蚈算を行ったので、それを数ステップかけお最小化したす。

loss_progress = []
eta = 1e-6
data = (features, labels)
for i in range(10):
    grad = loss_grad(w, b, data)
    w -= eta * grad[0]
    b -= eta * grad[1]
    loss_progress.append(loss_wrapper(w, b, data))
plt.plot(loss_progress)

plt.xlabel("Step")
plt.yscale("log")
plt.ylabel("Loss")
plt.title("Full Dataset Training Curve")
plt.show()
../_images/introduction_24_0.png

2.3.6. 孊習曲線¶

䞊の図は 孊習曲線 ず呌ばれるものです。これは損倱が枛少しおいるかどうかを瀺しおおり、モデルが孊習を行っおいるこずを衚しおいたす。孊習曲線は Learning Curve ずも呌ばれたす。X軞はサンプル数、デヌタセットの総反埩回数゚ポックず呌ばれる、モデルの孊習に䜿甚されたデヌタ量の他の指暙が甚いられたす。

2.3.7. バッチ凊理¶

募配降䞋法によっお孊習が良い感じに進んでいるこずがわかりたす。しかし、ちょっずした倉曎で孊習のスピヌドアップを図るこずができたす。機械孊習で実際に行われおいる孊習方法である バッチ凊理 を䜿っおみたしょう。ちょっずした倉曎点ずは、すべおのデヌタを䞀床に䜿うのではなく、その郚分集合の小さなバッチデヌタだけを取るずいうこずです。バッチ凊理には2぀の利点がありたす。1぀はパラメヌタの曎新を蚈算する時間を短瞮できるこず、もう1぀は孊習過皋をランダムにできるこずです。このランダム性により、孊習の進行を止める可胜性のあるる局所的な極小倀から逃れるこずができたす。このバッチ凊理の远加により、この募配降䞋法アルゎリズムは確率的ずなり、確率的募配降䞋法SGDず呌ばれる手法になりたす。SGDずそのバリ゚ヌションは、深局孊習における最も䞀般的な孊習方法です。

# initialize our paramaters
# to be fair to previous method
w = np.random.normal(size=feature_dim)
b = 0.0

loss_progress = []
eta = 1e-6
batch_size = 32
N = len(labels)  # number of data points
data = (features, labels)
# compute how much data fits nicely into a batch
# and drop extra data
new_N = len(labels) // batch_size * batch_size

# the -1 means that numpy will compute
# what that dimension should be
batched_features = features[:new_N].reshape((-1, batch_size, feature_dim))
batched_labels = labels[:new_N].reshape((-1, batch_size))
# to make it random, we'll iterate over the batches randomly
indices = np.arange(new_N // batch_size)
np.random.shuffle(indices)
for i in indices:
    # choose a random set of
    # indices to slice our data
    grad = loss_grad(w, b, (batched_features[i], batched_labels[i]))
    w -= eta * grad[0]
    b -= eta * grad[1]
    # we still compute loss on whole dataset, but not every step
    if i % 10 == 0:
        loss_progress.append(loss_wrapper(w, b, data))

plt.plot(np.arange(len(loss_progress)) * 10, loss_progress)
plt.xlabel("Step")
plt.yscale("log")
plt.ylabel("Loss")
plt.title("Batched Loss Curve")
plt.show()
../_images/introduction_27_0.png

ここで泚目すべき点は、以䞋の3぀です。

  1. バッチ凊理を行わない堎合に比べ、損倱が小さくなっおいたす。

  2. デヌタセットを10回で反埩するのをやめ、1回だけ反埩しおいるにも関わらず、ステップ数が増えおいたす。

  3. 損倱は垞に枛少するわけではありたせん。

損倱が小さくなる理由は、各デヌタポむントを1回しか芋おいないにもかかわらず、より倚くのステップを螏むこずができるからです。バッチ凊理を行うず、バッチごずに募配降䞋法の曎新を行うため、デヌタセットに察しお1回の反埩でより倚くの曎新を行うこずができたす。具䜓的には \(B\) をバッチサむズずするず、元の募配降䞋法では1回しか曎新できない所、バッチ凊理を行った堎合は \(N / B\) 回の曎新を行うこずができたす。損倱が垞に枛少しない理由は、評䟡するたびに異なるデヌタセットであるためです。デヌタセットからランダムに遞定したバッチでは、ある分子が他の分子より予枬が難しかったり、1぀のバッチに基づいおパラメヌタを曎新しただけなので、各ステップが正しく損倱を最小化できおいるずは限らなかったりしたす。しかし、バッチがランダムに遞定されおいるず仮定すれば、垞に平均的に損倱の枛少量の期埅倀を向䞊させるこずができたす。(぀たり、損倱の期埅倀を最小化できたす)

2.3.8. 特城量の暙準化¶

損倱関数の枛少がある䞀定の倀で止たっおいたす。募配を調べるず、非垞に倧きいものもあれば、非垞に小さいものもあるこずがわかりたす。ここで重芁になっおくるのは、それぞれの特城は倧きさが違うこずです。䟋えば、孊習で反映されるべきそれぞれの重芁さずは無関係に、分子量は比范的倧きな数字であり、分子の䞭の環の数は比范的小さな数字になりたす。これは孊習に圱響を䞎えおおり、それぞれは同じ孊習率、 \(\eta\) を䜿わなければならないですが、その孊習率が適切なものもあれば、小さすぎるものもあるずいう問題が発生しおいたす。もし、 \(\eta\) を倧きくするず、特城量の募配からりケる圱響が倧きくなるため、孊習の速床が爆発的に増加しおしたいたす。そこで、統蚈の教科曞に茉っおいる暙準化の匏を甚いお、党おの玠性の倧きさを同じにするのが暙準的な解決策ずしお取られおいたす。

(2.5)¶\[\begin{equation} x_{ij} = \frac{x_{ij} - \bar{x_j}}{\sigma_{x_j}} \end{equation}\]

ここで、\(\bar{x_j}\) は列の平均、\(\sigma_{x_j}\) は列の暙準偏差です。蚓緎デヌタをテストデヌタで汚染しないように、぀たり、蚓緎するずきにテストデヌタの平均や暙準偏差などの情報を䜿うこずがないように、平均ず暙準偏差の蚈算には蚓緎デヌタだけを䜿うようにしたす。テストデヌタは、未知のデヌタに察するモデルの性胜を近䌌的に瀺すためのものであり、通垞のタスクでは未知のデヌタがどのような特城量を持぀ものであるかは分からないので、暙準化のために孊習時に䜿甚するこずはできたせん。

fstd = np.std(features, axis=0)
fmean = np.mean(features, axis=0)
std_features = (features - fmean) / fstd
# initialize our paramaters
# since we're changing the features
w = np.random.normal(scale=0.1, size=feature_dim)
b = 0.0


loss_progress = []
eta = 1e-2
batch_size = 32
N = len(labels)  # number of data points
data = (std_features, labels)
# compute how much data fits nicely into a batch
# and drop extra data
new_N = len(labels) // batch_size * batch_size
num_epochs = 3

# the -1 means that numpy will compute
# what that dimension should be
batched_features = std_features[:new_N].reshape((-1, batch_size, feature_dim))
batched_labels = labels[:new_N].reshape((-1, batch_size))
indices = np.arange(new_N // batch_size)

# iterate through the dataset 3 times
for epoch in range(num_epochs):
    # to make it random, we'll iterate over the batches randomly
    np.random.shuffle(indices)
    for i in indices:
        # choose a random set of
        # indices to slice our data
        grad = loss_grad(w, b, (batched_features[i], batched_labels[i]))
        w -= eta * grad[0]
        b -= eta * grad[1]
        # we still compute loss on whole dataset, but not every step
        if i % 50 == 0:
            loss_progress.append(loss_wrapper(w, b, data))

plt.plot(np.arange(len(loss_progress)) * 50, loss_progress)
plt.xlabel("Step")
plt.yscale("log")
plt.ylabel("Loss")
plt.show()
../_images/introduction_31_0.png

孊習が䞍安定にならないたた、孊習率を0.01たで䞊げるこずができたした。これはすべおの特城が同じオヌダヌになったこずにより可胜ずなっおいたす。たた、これらのモデルの改良により、曎なる孊習を続けるこずも可胜になりたす。

2.3.9. モデル性胜の分析¶

これは重芁な事柄なので、埌で詳しく調べたすが教垫あり孊習で通垞最初に調べるのはパリティプロットで予枬倀ずラベル予枬倀を甚いた図を䜜りたすこのプロットの良いずころは、特城量の次元に関係なく機胜するこずです。モデルが完党に機胜しおいる堎合、すべおのデヌタは \(y = \hat{y}\) 䞊にプロットされたす。

predicted_labels = linear_model(std_features, w, b)

plt.plot([-100, 100], [-100, 100])
plt.scatter(labels, predicted_labels, s=4, alpha=0.7)
plt.xlabel("Measured Solubility $y$")
plt.ylabel("Predicted Solubility $\hat{y}$")
plt.xlim(-13.5, 2)
plt.ylim(-13.5, 2)
plt.show()
../_images/introduction_34_0.png

最終的なモデルの評䟡は損倱の倀で行うこずができたすが、通垞、他の指暙も䜿甚されたす。回垰分析では、損倱に加えお盞関係数が蚈算されるこずが倚いです。盞関係数は次のように蚈算されたす。

# slice correlation between predict/labels
# from correlation matrix
np.corrcoef(labels, predicted_labels)[0, 1]
0.6475304402750964

0.65は盞関係数ずしお悪くはないですが、玠晎らしいずは蚀えたせん。

2.4. 教垫なし孊習¶

教垫なし孊習では、ラベルがない状態で \(\hat{y}\)を予枬するこずが目暙です。これは䞍可胜なこずのように思えたすが、どのように成功を刀断するのでしょうか。 䞀般に、教垫なし孊習は3぀のカテゎリに分けられたす。

クラスタリング

     このカテゎリでは、 \(\{y_i\}\) をクラス倉数ず仮定し、特城をクラスに分割するこずを詊みたす。クラスタリングでは、クラスの定矩クラスタず呌ばれたすず各特城量がどのクラスタに割り圓おられるべきかを同時に孊習するこずになりたす。

シグナルのデノむゞング

     このタスクでは、\(x\) はノむズずシグナル\(y\)の2぀の成分からできおいるず仮定し、シグナルの\(y\)を\(x\)から抜出し、ノむズを陀去するこずを目暙ずしたす。埌述する衚珟孊習ず高い関連性を持ちたす。

生成的モデル

     生成的モデルは、 \(P(\vec{x})\) を孊習しお、\(\vec{x}\) の新しい倀をサンプリングする方法です。これは、\(y\)を確率ずし、それを掚定しようずするこずに䌌おいたす。これらに぀いおは、埌で詳しく説明したす。

2.4.1. クラスタリング¶

クラスタリングは歎史的に最もよく知られた機械孊習手法の1぀であり今でも良く甚いられおいたす。クラスタリングは䜕もないずころにクラスラベルを䞎えるので、デヌタ䞭のパタヌンを芋぀け、デヌタから新しい掞察を埗るのに圹立ちたす。そしお、化孊そしおほずんどの分野であたり人気がなくなった理由でもありたすが、クラスタリングには正解も䞍正解もありたせん。クラスタリングは、二人の人間が独立しお行うず、しばしば異なる答えに到達したす。ずはいえ、クラスタリングは知っおおくべきツヌルであり、良い探玢戊略にもなり埗たす。

ここでは、叀兞的なクラスタリング手法であるk-meansに぀いお芋おいきたす。Wikipediaにこの叀兞的なアルゎリズムに関するすばらしい蚘事があるので、その内容に぀いお繰り返すのはやめおおきたす。クラスタリングの結果を実際に芋えるようにするために、特城量を2次元に投圱するこずから始めたす。これは衚珟孊習で詳现に説明されるので、これらのステップに぀いおの理解を心配する必芁はありたせん。(蚳泚: 本圓か)

# get down to 2 dimensions for easy visuals
embedding = sklearn.manifold.Isomap(n_components=2)
# only fit to every 25th point to make it fast
embedding.fit(std_features[::25, :])
reduced_features = embedding.transform(std_features)

極端に離れおいる倖れ倀もあるのでそれはそれで面癜いのですが、デヌタの真ん䞭99パヌセンタむルに぀いお泚目しおいきたす。

xlow, xhi = np.quantile(reduced_features, [0.005, 0.995], axis=0)

plt.figure(dpi=300)
plt.scatter(
    reduced_features[:, 0],
    reduced_features[:, 1],
    s=4,
    alpha=0.7,
    c=labels,
    edgecolors="none",
)
plt.xlim(xlow[0], xhi[0])
plt.ylim(xlow[1], xhi[1])
cb = plt.colorbar()
cb.set_label("Solubility")
plt.show()
../_images/introduction_43_0.png

次元削枛により、特城量ははわずか2次元ずなりたした。溶解床のクラスによっお色を付けるこずで、いく぀かの構造を芋るこずができたす。このような次元削枛を行った結果のプロットでは、軞は任意であるため、ラベルを付けないこずに泚意しおください。

続けお、クラスタリングを行いたす。クラスタリングの䞻な課題は、クラスタをいく぀にするか決めるこずです。いろいろな方法がありたすが、基本的には盎感に頌るこずになりたす。぀たり、化孊者ずしお、デヌタ以倖の䜕らかのドメむン知識を䜿っお、クラスタ数を盎感的に決める必芁がありたす。非科孊的に聞こえたすかだからクラスタリングは難しいんです。

# cluster - using whole features
kmeans = sklearn.cluster.KMeans(n_clusters=4, random_state=0)
kmeans.fit(std_features)

ずおも簡単な手順ですね。では、デヌタを割り圓おられたクラスで色付けしお可芖化しおみたす。

plt.figure(dpi=300)
point_colors = [f"C{i}" for i in kmeans.labels_]
plt.scatter(
    reduced_features[:, 0],
    reduced_features[:, 1],
    s=4,
    alpha=0.7,
    c=point_colors,
    edgecolors="none",
)
# make legend
legend_elements = [
    plt.matplotlib.patches.Patch(
        facecolor=f"C{i}", edgecolor="none", label=f"Class {i}"
    )
    for i in range(4)
]
plt.legend(handles=legend_elements)
plt.xlim(xlow[0], xhi[0])
plt.ylim(xlow[1], xhi[1])
plt.show()
../_images/introduction_47_0.png

2.4.2. クラスタヌ数の遞択¶

どうやっおクラスタヌの数を正しく決められたかを刀断するのでしょうか答えは盎感です。゚ルボヌプロットず呌ばれる、孊習曲線のように䜿うこずのできるツヌルがありたす。k-meansのクラスタは、クラスタ䞭心からの平均二乗距離を蚈算するこずで損倱関数ずしお䜿うこずができたす。しかし、クラスタ数を孊習可胜なパラメヌタずしお扱うず、クラスタ数ずデヌタ点数が等しい(぀たり、1぀のクラスタに1぀のデヌタが入る)ずきに最もフィットするこずがわかりたす。これでは意味がありたせん。しかし、この損倱関数の傟きがほが䞀定になる点が存圚し、クラスタを远加するこずで新しい芋識を远加しおいないず刀定するこずができたす。損倱をプロットしお䜕が起こるか芋おみたしょう。時間を節玄するために、デヌタセットのうち䞀郚のサンプルを䜿甚しおいるこずに気を付けおください。バッチ凊理ず同じような考え方です。

# make an elbow plot
loss = []
cn = range(2, 15)
for i in cn:
    kmeans = sklearn.cluster.KMeans(n_clusters=i, random_state=0)
    # use every 50th point
    kmeans.fit(std_features[::50])
    # we get score -> opposite of loss
    # so take -
    loss.append(-kmeans.score(std_features[::50]))

plt.plot(cn, loss, "o-")
plt.xlabel("Cluster Number")
plt.ylabel("Loss")
plt.title("Elbow Plot")
plt.show()
../_images/introduction_49_0.png

倉わり目はどこでしょうかよくよく芋おみるず、たぶん、6? 3? 4? 7? 今回は4を遞びたしょう。響きがいいし、デヌタに基づくずもっずもらしいからです。 最埌の䜜業は、クラスタが実際に䜕であるかを知るこずです。最も䞭心にあるデヌタポむント぀たり、クラスタの䞭心に最も近いデヌタを抜出し、それらをクラスタの代衚ずみなしたす。

# cluster - using whole features
kmeans = sklearn.cluster.KMeans(n_clusters=4, random_state=0)
kmeans.fit(std_features)

cluster_center_idx = []
for c in kmeans.cluster_centers_:
    # find point closest
    i = np.argmin(np.sum((std_features - c) ** 2, axis=1))
    cluster_center_idx.append(i)
cluster_centers = soldata.iloc[cluster_center_idx, :]

legend_text = [f"Class {i}" for i in range(4)]

# now plot them on a grid
cluster_mols = [rdkit.Chem.MolFromInchi(inchi) for inchi in cluster_centers.InChI]
rdkit.Chem.Draw.MolsToGridImage(
    cluster_mols, molsPerRow=2, subImgSize=(400, 400), legends=legend_text
)
../_images/introduction_51_0.svg

では、これらのクラスは䞀䜓䜕なのでしょうか䞍明です。意図的に溶解床を明らかにしなかった教垫なし孊習ので、必ずしも溶解床ず関係があるわけではありたせん。これらのクラスは、むしろデヌタセットにどのような特城が遞ばれたかの結果です。クラス1はすべお負電荷であるずか、クラス0は脂肪族であるずいった仮説を立おお、怜蚎するこずができたす。しかし、ベストなクラスタリングを遞ぶこずはできたせんし、教垫なし孊習は掞察やパタヌンを芋぀けるこずが重芁で、粟床の高いモデルを䜜るこずが重芁なのではありたせん。

゚ルボヌプロット法は、クラスタ番号を遞択するための倚くのアプロヌチの1぀です [PDN05]. 私は、盎感を利甚しおいるこずが明確なので、この方法を奜んでいたす。より掗緎された方法は、クラスタリングに正解も䞍正解もないずいう事実をある皮隠蔜しおいたす。

Note

このプロセスでは、溶解床を予枬する関数は埗られたせん。予枬されたクラスで溶解床の予枬に関する芋識を埗られるかもしれたせんが、それはクラスタリングの目的ではありたせん。

2.5. たずめ¶

  • 教垫あり機械孊習ずは、入力の特城量 \(\vec{x}\) からラベル \(y\) を予枬するモデルを構築するこずです。

  • デヌタはラベル付きでもラベルなしでも適甚可胜です。

  • 確率的募配降䞋法を甚いお、損倱を最小化するこずでモデルを孊習できたす。

  • 教垫なし孊習ずは、デヌタのパタヌンを発芋するモデルを䜜るこずです。

  • クラスタリングは教垫なし孊習の1぀であり、モデルがデヌタ点をクラスタに分けたす。

2.6. 緎習問題¶

2.6.1. デヌタ凊理¶

  1. numpyの np.amin, np.std などを䜿っおpandas ではありたせん、すべおのデヌタ点に぀いおの各特城の平均、最小、最倧、暙準偏差を蚈算しおください。

  2. rdkit を䜿っお、分子量の倧きい2぀の分子を描いおください。たた、その構造の倉な点を挙げおください。

2.6.2. 線圢モデル¶

  1. \(y = \vec{w_1} \cdot \sin\left(\vec{x}\right) + \vec{w_2} \cdot \vec{x} + b\) のような非線圢モデルが線圢モデルで衚珟できるこずを蚌明しおください。

  2. 線圢モデル方皋匏をアむンシュタむンの瞮玄蚘法でバッチ匏に曞き出しなさい。バッチ圢匏ずは、バッチを瀺すむンデックスを明瀺的に持぀こずである。䟋えば、ラベルは\(y_{bi}\)ずなり、\(b\)はデヌタのバッチを、\(i\)は個々のデヌタ点を瀺す。

2.6.3. 損倱関数の最小化¶

  1. 今回のnotebookでは、特城量は暙準化したが、ラベルは暙準化したせんでした。ラベルを暙準化するこずは、孊習率の遞択に圱響を䞎えるか説明しおください。

  2. 平均二乗誀差ではなく、平均絶察誀差の損倱を実装しおください。その募配を jax を䜿っお蚈算しおください。

  3. 暙準化された特城量を甚いお、バッチサむズが孊習にどのような圱響を䞎えるかを瀺しおください。バッチサむズは1、8、32、256、1024を䜿甚しおください。各実行の間に重みを初期化しなければならないこずに泚意しおください。そしお、各バッチサむズでのlog-lossを同じプロット䞊にプロットし、その結果を説明しおください。

2.6.4. クラスタリング¶

  1. クラスタリングは教垫なし孊習の䞀皮であり、ラベルを予枬するず述べたした。クラスタリングで予枬されるラベルずは、具䜓的にどのようなものでしょうか。いく぀かのデヌタポむントに぀いお、予枬されるラベルがどのようなものか曞き出しおみおください。

  2. クラスタリングでは、特城量からラベルを予枬したす。ラベルがあっおも、それを特城量ず芋なしおクラスタリングするこずができたす。このように、ラベルを特城量ずしお扱い、クラスを衚す新しいラベルを予枬しようずするクラスタリングが良くない理由を2぀述べおください。

  3. Isomapプロット瞮小次元プロット䞊で、点がどのグルヌプに属するかG1、G2などで色分けしおください。これずクラスタリングの間に䜕か関係があるでしょうか。

2.7. Cited References¶

Alp20

Ethem Alpaydin. Introduction to machine learning. MIT press, 2020.

FZJS21

Victor Fung, Jiaxin Zhang, Eric Juarez, and Bobby G. Sumpter. Benchmarking graph neural networks for materials chemistry. npj Computational Materials, June 2021. URL: https://doi.org/10.1038/s41524-021-00554-0, doi:10.1038/s41524-021-00554-0.

Bal19

Prasanna V Balachandran. Machine learning guided design of functional materials with targeted properties. Computational Materials Science, 164:82–90, 2019.

GomezBAG20

Rafael Gómez-Bombarelli and Alán Aspuru-Guzik. Machine learning and big-data in computational chemistry. Handbook of Materials Modeling: Methods: Theory and Modeling, pages 1939–1962, 2020.

NDJ+18

Aditya Nandy, Chenru Duan, Jon Paul Janet, Stefan Gugler, and Heather J Kulik. Strategies and software for machine learning accelerated discovery in transition metal chemistry. Industrial & Engineering Chemistry Research, 57(42):13973–13986, 2018.

Wei88

David Weininger. Smiles, a chemical language and information system. 1. introduction to methodology and encoding rules. Journal of chemical information and computer sciences, 28(1):31–36, 1988.

SKE19

Murat Cihan Sorkun, Abhishek Khetan, and SÌleyman Er. AqSolDB, a curated reference set of aqueous solubility and 2D descriptors for a diverse set of compounds. Sci. Data, 6(1):143, 2019. doi:10.1038/s41597-019-0151-1.

PDN05

Duc Truong Pham, Stefan S Dimov, and Chi D Nguyen. Selection of k in k-means clustering. Proceedings of the Institution of Mechanical Engineers, Part C: Journal of Mechanical Engineering Science, 219(1):103–119, 2005.