Skip to main content

Optunaインテグレーションによる材料配合最適化

Created on December 17|Last edited on December 18


1. テーマ概要

マテリアルズ・インフォマティクスの分野では、機械学習モデルによる物性予測とベイズ最適化などの最適化ソルバーの組み合わせにより、新素材開発などの用途で最適な配合提案を行うといった手法が知られています。
今回、UC Irvine Machine Learning Repositoryで公開されているコンクリートの圧縮強度予測用のデータセット(https://archive.ics.uci.edu/dataset/165/concrete+compressive+strength)を用いて、コンクリートの圧縮強度を最大化するための材料配合最適化のデモを行います。
最適化ソルバーとしてOptunaを利用しつつ、OptunaのW&Bインテグレーション機能を利用することで、最適化の進捗状況や最適化結果の可視化を行います。

2. 実行手順

2-1. 予測モデルの作成

何はともあれ予測モデルを作成します。
今回のデモでは特にモデルの部分はこだわらず(実際の業務ではここが最も肝心ですが)、簡単な線形モデルで学習します。

2-1-1. 必要なモジュールのimportとデータセットの準備

import pandas as pd
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.model_selection import train_test_split
from sklearn import linear_model
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score
import wandb
from joblib import dump

wb_project_name = "concrete-strength-optimization-demo"

run = wandb.init(project=wb_project_name)

df_train = pd.read_excel("dataset/Concrete_Data.xls")

X = df_train.iloc[:, :-1]
y = df_train.iloc[:, -1]

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)

# 学習データをW&Bのテーブルとして登録します
run.log({"training_data": wandb.Table(dataframe=pd.concat([X_train, y_train], axis=1).sort_index())})

Run set
1


2-1-2. 学習の実行

リッジ回帰でモデルを作り、後続の最適化時に使用するためアーティファクトでモデルを保存しておきます。
# 学習実行
model = Pipeline([('scaler', StandardScaler()), ('ridge', linear_model.Ridge(alpha=0.0))]).fit(X_train, y_train)

# モデル出力
model_file_path = 'model.joblib'
dump(pipe, model_file_path)

# モデルをArtifactに保存
model_artifact = wandb.Artifact(
"ridge", type="model",
description="Simple Ridge with StandardScaler",
metadata=dict(wandb.config))
model_artifact.add_file(model_file_path)
run.log_artifact(model_artifact)

2-1-3. 精度評価

精度評価結果をログし、使用した検定データをテーブルで保存しておきます。
精度はR2で0.62と高くは無いですが、一旦こちらで進めます。
# 予測実行・精度評価
y_test_pred = pipe.predict(X_test)
run.log({
"RMSE": mean_squared_error(y_test, y_test_pred, squared=False),
"MAE": mean_absolute_error(y_test, y_test_pred),
"R2": r2_score(y_test, y_test_pred),
})

# 検定データをW&Bのテーブルで保存
df_valid = pd.concat([X_test, y_test, pd.Series(y_test_pred, name="pred", index=X_test.index)], axis=1).sort_index()
run.log({"valid_data": wandb.Table(dataframe=df_valid)})

Run set
1


2-2. 最適化/の実行

続いてOptunaを利用した配合最適化を実行します。
OptunaのWandBインテグレーションの機能として、WeightsAndBiasesCallbackを利用します。

2-2-1. 必要なライブラリのImport

from joblib import load
from pathlib import Path
import pandas as pd
import plotly.express as px
import wandb
import optuna
from optuna.integration.wandb import WeightsAndBiasesCallback

2-2-2. アーティファクトに保存していた予測モデルをロード

wb_project_name = "concrete-strength-optimization-demo"

def load_model():
with wandb.init(project=wb_project_name) as run:
artifact = run.use_artifact("ridge:latest", type="model")
artifact_dir = artifact.download()
return load(Path(artifact_dir) / "model.joblib")

model = load_model()

2-2-3. 最適化の探索対象パラメータ・固定パラメータを設定

今回は、最適化の条件として Age(day) を 60 で固定し、その他の材料組成を探索対象とします。
探索の範囲(最大・最小)はlimits変数に格納しておきます。
# 学習データを読み込む
df_train = pd.read_excel("dataset/Concrete_Data.xls")

# 学習データの各変数の最大値・最小値の辞書
limits = {col: [df_train.min()[col], df_train.max()[col]] for col in df_train.columns}

# 目的変数
target = 'Concrete compressive strength(MPa, megapascals) '

# 目的変数を除く特徴量のリスト
features = list(df_train.drop(columns=[target]).columns)

# 固定パラメータの辞書(今回は'Age (day)'を60で固定)
fixed_features = {'Age (day)': 60}

# 探索対象パラメータ名のリスト
control_features = [col for col in features if col not in fixed_features]

2-2-4. 最適化の実行

multirunモードをOn(as_multirun=True)として100イテレーション計算を回します(n_trials=100)。
圧縮強度を最大化するため、評価関数(objectiveの戻り値)は予測結果の符号反転値としています。
def suggest(trial, col):
if col in control_features:
return trial.suggest_float(col, limits[col][0], limits[col][1])
return fixed_features[col]

def optimize():
wandb_kwargs = {"project": wb_project_name}

wandbc = WeightsAndBiasesCallback(wandb_kwargs=wandb_kwargs, as_multirun=True)
@wandbc.track_in_wandb()
def objective(trial):
df_suggest = pd.DataFrame({col: [suggest(trial, col)] for col in features})
return - model.predict(df_suggest)
study = optuna.create_study()
study.optimize(objective, n_trials=100, callbacks=[wandbc])

optimize()
multirunモードがOnの場合、計算のイテレーション(Trial)毎にW&Bのrunが生成され、W&Bのダッシュボード上でrun毎の結果をインタラクティブに比較できる事がわかります。
上図:横軸=イテレーション、縦軸=スコア で表示した散布図。52イテレーション目で最適値(-131.212)となった事がわかる
下図:各イテレーションで提案された配合組成の組み合わせを平行軸座標プロットで表示したもの。

Run set
107


3. まとめ

今回はコンクリートの材料配合最適化をテーマに、W&BとOptunaを使った逆問題解析についてご紹介しました。
一般的なW&Bの用途とは少し毛色の異なるテーマではありますが、ログするデータを工夫することで様々な用途にW&Bを利用できるという事がわかりますよね。こちらの記事をご覧になった皆様もぜひご自身のテーマに照らし合わせて応用先を考えていただければ幸いです。
それでは皆様良いクリスマスをお過ごしください!