第4章:材料探索への応用と実践

ベイズ最適化・DFT・実験ロボットとの統合

📖 読了時間: 25-30分 📊 難易度: 上級 💻 コード例: 7個 📝 演習問題: 3問

第4章:材料探索への応用と実践

ベイズ最適化・DFT・実験ロボットとの統合

学習目標

この章を読むことで、以下を習得できます:

読了時間: 25-30分 コード例: 7個 演習問題: 3問


4.1 Active Learning × ベイズ最適化

ベイズ最適化との統合

Active LearningとBayesian Optimizationは密接に関連しています。

共通点: - 不確実性を活用した賢いサンプリング - ガウス過程による代理モデル - 獲得関数で次候補を選択

違い: - Active Learning: モデル改善が目的 - Bayesian Optimization: 目的関数の最大化が目的

BoTorchによる統合実装

コード例1: Active Learning + ベイズ最適化

import torch
import numpy as np
from botorch.models import SingleTaskGP
from botorch.acquisition import UpperConfidenceBound, qExpectedImprovement
from botorch.optim import optimize_acqf
from botorch.fit import fit_gpytorch_model
from gpytorch.mlls import ExactMarginalLogLikelihood
from sklearn.metrics import mean_squared_error


class ActiveBayesianOptimizer:
    """Active Learning統合型ベイズ最適化器"""

    def __init__(self, bounds, mode='exploration'):
        """
        Parameters
        ----------
        bounds : torch.Tensor
            探索空間の境界 (2 x d: [下限, 上限])
        mode : str
            'exploration' (Active Learning) or 'exploitation' (BO)
        """
        self.bounds = bounds
        self.mode = mode
        self.train_X = None
        self.train_Y = None
        self.model = None

    def fit(self, X, Y):
        """GPモデルを学習データに適合"""
        self.train_X = torch.tensor(X, dtype=torch.float64)
        self.train_Y = torch.tensor(Y, dtype=torch.float64).unsqueeze(-1)

        # SingleTaskGPモデルの構築
        self.model = SingleTaskGP(self.train_X, self.train_Y)
        mll = ExactMarginalLogLikelihood(self.model.likelihood, self.model)
        fit_gpytorch_model(mll)

    def suggest_next(self, n_candidates=1):
        """次の実験候補を提案"""
        if self.mode == 'exploration':
            # Active Learning: 不確実性重視
            acq_function = UpperConfidenceBound(
                self.model, beta=2.0  # 高いbeta = 探索重視
            )
        else:
            # Bayesian Optimization: 改善重視
            acq_function = qExpectedImprovement(
                self.model, best_f=self.train_Y.max()
            )

        # 獲得関数を最大化
        candidates, acq_value = optimize_acqf(
            acq_function,
            bounds=self.bounds,
            q=n_candidates,
            num_restarts=20,
            raw_samples=512,
        )

        return candidates.numpy(), acq_value.item()

    def predict(self, X_test):
        """テストデータの予測と不確実性"""
        X_test_tensor = torch.tensor(X_test, dtype=torch.float64)
        with torch.no_grad():
            posterior = self.model.posterior(X_test_tensor)
            mean = posterior.mean.numpy()
            variance = posterior.variance.numpy()
        return mean, np.sqrt(variance)


# 使用例: 材料物性の最適化
def bandgap_oracle(X):
    """仮想的なバンドギャップ計算(実際はDFT)"""
    return 2.0 * np.sin(X[:, 0] * 3) + np.cos(X[:, 1] * 2) + np.random.normal(0, 0.1, X.shape[0])


# 初期データ(ランダムサンプリング)
np.random.seed(42)
bounds = torch.tensor([[0.0, 0.0], [5.0, 5.0]], dtype=torch.float64)
X_init = np.random.uniform(0, 5, (10, 2))
Y_init = bandgap_oracle(X_init)

# オプティマイザの初期化
optimizer = ActiveBayesianOptimizer(bounds, mode='exploration')
optimizer.fit(X_init, Y_init)

# Active Learningループ(10回)
X_train = X_init.copy()
Y_train = Y_init.copy()

for iteration in range(10):
    # 次の候補を提案
    X_next, acq_val = optimizer.suggest_next(n_candidates=1)

    # 実験実行(または計算)
    Y_next = bandgap_oracle(X_next)

    # データ追加
    X_train = np.vstack([X_train, X_next])
    Y_train = np.append(Y_train, Y_next)

    # モデル再学習
    optimizer.fit(X_train, Y_train)

    print(f"Iteration {iteration + 1}:")
    print(f"  Next X: {X_next[0]}")
    print(f"  Measured Y: {Y_next[0]:.3f}")
    print(f"  Acquisition Value: {acq_val:.3f}")
    print(f"  Best Y so far: {Y_train.max():.3f}\n")

# 最終性能評価
X_test = np.random.uniform(0, 5, (100, 2))
Y_test = bandgap_oracle(X_test)
Y_pred, Y_std = optimizer.predict(X_test)
rmse = np.sqrt(mean_squared_error(Y_test, Y_pred.squeeze()))

print("=" * 50)
print(f"Final Model Performance:")
print(f"  Test RMSE: {rmse:.4f}")
print(f"  Best bandgap found: {Y_train.max():.3f}")
print(f"  at composition: {X_train[Y_train.argmax()]}")

出力例:

Iteration 1:
  Next X: [2.87 4.12]
  Measured Y: 2.456
  Acquisition Value: 1.823
  Best Y so far: 2.851

Iteration 2:
  Next X: [1.23 3.45]
  Measured Y: 2.912
  Acquisition Value: 1.654
  Best Y so far: 2.912

...

==================================================
Final Model Performance:
  Test RMSE: 0.1872
  Best bandgap found: 3.124
  at composition: [4.21 2.89]

4.2 Active Learning × 高スループット計算

DFT計算の効率化

課題: DFT計算は1サンプル数時間〜数日

解決策: Active Learningで計算すべきサンプルを優先順位付け

コード例2: DFT計算の優先順位付け

import numpy as np
import pandas as pd
from sklearn.gaussian_process import GaussianProcessRegressor
from sklearn.gaussian_process.kernels import RBF, ConstantKernel
from pymatgen.core import Composition
from mp_api.client import MPRester
from typing import List, Tuple, Dict


class DFTPrioritizer:
    """DFT計算を優先順位付けするActive Learningシステム"""

    def __init__(self, api_key: str = None):
        """
        Parameters
        ----------
        api_key : str
            Materials Project APIキー
        """
        self.api_key = api_key
        self.gp_model = None
        self.calculated_materials = []
        self.pending_materials = []

    def fetch_candidate_materials(
        self,
        elements: List[str],
        max_candidates: int = 100
    ) -> pd.DataFrame:
        """Materials Projectから候補材料を取得"""
        if self.api_key:
            with MPRester(self.api_key) as mpr:
                # 既知材料を検索
                docs = mpr.materials.summary.search(
                    elements=elements,
                    fields=["material_id", "formula_pretty", "band_gap",
                            "formation_energy_per_atom", "energy_above_hull"]
                )

                candidates = []
                for doc in docs[:max_candidates]:
                    candidates.append({
                        'material_id': doc.material_id,
                        'formula': doc.formula_pretty,
                        'bandgap': doc.band_gap,
                        'formation_energy': doc.formation_energy_per_atom,
                        'stability': doc.energy_above_hull
                    })

                return pd.DataFrame(candidates)
        else:
            # デモ用ダミーデータ
            print("Warning: No API key provided, using dummy data")
            return self._generate_dummy_materials(elements, max_candidates)

    def _generate_dummy_materials(
        self,
        elements: List[str],
        n: int
    ) -> pd.DataFrame:
        """デモ用のダミー材料データを生成"""
        np.random.seed(42)
        materials = []

        for i in range(n):
            # ランダムな組成
            composition = {elem: np.random.randint(1, 4) for elem in elements}
            formula = ''.join([f"{k}{v}" for k, v in composition.items()])

            materials.append({
                'material_id': f'mp-{10000 + i}',
                'formula': formula,
                'bandgap': None,  # 未計算
                'formation_energy': np.random.uniform(-3, 0),
                'stability': np.random.uniform(0, 0.5)
            })

        return pd.DataFrame(materials)

    def featurize(self, df: pd.DataFrame) -> np.ndarray:
        """組成から記述子を生成"""
        features = []

        for formula in df['formula']:
            comp = Composition(formula)
            # 簡易的な記述子: 元素割合
            elem_dict = comp.get_el_amt_dict()
            total = sum(elem_dict.values())

            # 主要元素の割合を特徴量に
            feature_vec = [
                elem_dict.get('Li', 0) / total,
                elem_dict.get('Co', 0) / total,
                elem_dict.get('O', 0) / total,
                elem_dict.get('Mn', 0) / total,
                comp.num_atoms,  # 原子数
                comp.average_electroneg,  # 平均電気陰性度
            ]
            features.append(feature_vec)

        return np.array(features)

    def train_surrogate_model(self, X_train: np.ndarray, y_train: np.ndarray):
        """代理モデル(GP)を学習"""
        kernel = ConstantKernel(1.0) * RBF(length_scale=1.0)
        self.gp_model = GaussianProcessRegressor(
            kernel=kernel,
            n_restarts_optimizer=10,
            alpha=0.1
        )
        self.gp_model.fit(X_train, y_train)

    def prioritize_by_uncertainty(
        self,
        candidates_df: pd.DataFrame,
        top_k: int = 10
    ) -> pd.DataFrame:
        """不確実性に基づいて計算優先順位を付与"""
        if self.gp_model is None:
            raise ValueError("Surrogate model not trained yet")

        # 特徴量化
        X_candidates = self.featurize(candidates_df)

        # 予測と不確実性
        y_pred, y_std = self.gp_model.predict(X_candidates, return_std=True)

        # 結果を追加
        candidates_df = candidates_df.copy()
        candidates_df['predicted_bandgap'] = y_pred
        candidates_df['uncertainty'] = y_std

        # 不確実性でソート(降順)
        prioritized = candidates_df.sort_values('uncertainty', ascending=False)

        return prioritized.head(top_k)

    def simulate_dft_calculation(self, material_id: str) -> float:
        """DFT計算をシミュレート(実際はVASP/Quantum Espresso実行)"""
        # ダミー計算:ランダムなバンドギャップ
        np.random.seed(hash(material_id) % 2**32)
        return np.random.uniform(0.5, 4.0)


# 使用例: バッテリー材料のバンドギャップ計算
print("=" * 60)
print("DFT Active Learning Workflow")
print("=" * 60)

# 1. システム初期化
prioritizer = DFTPrioritizer(api_key=None)  # デモモード

# 2. 候補材料の取得
elements = ['Li', 'Co', 'O', 'Mn']
candidates = prioritizer.fetch_candidate_materials(elements, max_candidates=50)
print(f"\n[Step 1] Fetched {len(candidates)} candidate materials")
print(candidates.head())

# 3. 初期データ(少数のDFT計算済み)
initial_indices = np.random.choice(len(candidates), size=5, replace=False)
initial_df = candidates.iloc[initial_indices].copy()

# DFT計算実行(初期)
initial_bandgaps = []
for mat_id in initial_df['material_id']:
    bg = prioritizer.simulate_dft_calculation(mat_id)
    initial_bandgaps.append(bg)

initial_df['bandgap'] = initial_bandgaps
print(f"\n[Step 2] Initial DFT calculations: {len(initial_df)} materials")
print(initial_df[['formula', 'bandgap']])

# 4. 代理モデル学習
X_train = prioritizer.featurize(initial_df)
y_train = initial_df['bandgap'].values
prioritizer.train_surrogate_model(X_train, y_train)
print("\n[Step 3] Surrogate model trained")

# 5. Active Learningループ
remaining_candidates = candidates[~candidates['material_id'].isin(initial_df['material_id'])]
n_iterations = 3

for iteration in range(n_iterations):
    print(f"\n{'=' * 60}")
    print(f"Active Learning Iteration {iteration + 1}")
    print('=' * 60)

    # 優先順位付け
    top_priority = prioritizer.prioritize_by_uncertainty(
        remaining_candidates,
        top_k=5
    )

    print("\nTop 5 high-uncertainty materials for DFT:")
    print(top_priority[['formula', 'predicted_bandgap', 'uncertainty']])

    # DFT計算実行(最も不確実な1つ)
    next_material = top_priority.iloc[0]
    mat_id = next_material['material_id']
    true_bandgap = prioritizer.simulate_dft_calculation(mat_id)

    print(f"\n[DFT Calculation]")
    print(f"  Material: {next_material['formula']}")
    print(f"  Predicted: {next_material['predicted_bandgap']:.3f} eV")
    print(f"  Measured:  {true_bandgap:.3f} eV")
    print(f"  Error: {abs(true_bandgap - next_material['predicted_bandgap']):.3f} eV")

    # データ追加と再学習
    new_data = pd.DataFrame([{
        'material_id': mat_id,
        'formula': next_material['formula'],
        'bandgap': true_bandgap
    }])
    initial_df = pd.concat([initial_df, new_data], ignore_index=True)

    X_train = prioritizer.featurize(initial_df)
    y_train = initial_df['bandgap'].values
    prioritizer.train_surrogate_model(X_train, y_train)

    # 候補リストから削除
    remaining_candidates = remaining_candidates[
        remaining_candidates['material_id'] != mat_id
    ]

    print(f"\nModel updated with {len(initial_df)} materials")

print("\n" + "=" * 60)
print("Active Learning Complete")
print("=" * 60)
print(f"Total DFT calculations: {len(initial_df)}")
print(f"Remaining candidates: {len(remaining_candidates)}")
print(f"\nMaterials with bandgap > 2.5 eV (solar cell candidates):")
solar_candidates = initial_df[initial_df['bandgap'] > 2.5]
print(solar_candidates[['formula', 'bandgap']].sort_values('bandgap', ascending=False))

出力例:

============================================================
DFT Active Learning Workflow
============================================================

[Step 1] Fetched 50 candidate materials
  material_id    formula  bandgap  formation_energy  stability
0   mp-10000  Li2Co2O3       NaN           -1.456      0.123
1   mp-10001  LiCoO2Mn1      NaN           -2.134      0.087
...

[Step 2] Initial DFT calculations: 5 materials
         formula  bandgap
0       Li2Co2O3    2.345
3       LiMnO2      1.876
...

[Step 3] Surrogate model trained

============================================================
Active Learning Iteration 1
============================================================

Top 5 high-uncertainty materials for DFT:
        formula  predicted_bandgap  uncertainty
12   Li3Co1O2Mn1              2.123        0.845
8    Li1Co3O1Mn2              1.987        0.782
...

[DFT Calculation]
  Material: Li3Co1O2Mn1
  Predicted: 2.123 eV
  Measured:  2.456 eV
  Error: 0.333 eV

Model updated with 6 materials

============================================================
Active Learning Complete
============================================================
Total DFT calculations: 8
Remaining candidates: 42

Materials with bandgap > 2.5 eV (solar cell candidates):
        formula  bandgap
2   Li3Co1O2Mn1    2.456
0      Li2Co2O3    2.345

4.3 Active Learning × 実験ロボット

クローズドループ最適化

flowchart LR A[候補提案\nActive Learning] --> B[実験実行\nロボット] B --> C[測定・評価\nセンサー] C --> D[データ蓄積\nデータベース] D --> E[モデル更新\n機械学習] E --> F[獲得関数評価\n次候補選定] F --> A style A fill:#e3f2fd style B fill:#fff3e0 style C fill:#f3e5f5 style D fill:#e8f5e9 style E fill:#ffebee style F fill:#fce4ec

コード例3: クローズドループシステムの実装

import numpy as np
import pandas as pd
from datetime import datetime
from typing import Dict, List, Callable
from sklearn.gaussian_process import GaussianProcessRegressor
from sklearn.gaussian_process.kernels import RBF, ConstantKernel
import time


class ClosedLoopSystem:
    """自律材料探索のクローズドループシステム"""

    def __init__(
        self,
        experiment_function: Callable,
        feature_dim: int,
        bounds: np.ndarray
    ):
        """
        Parameters
        ----------
        experiment_function : Callable
            実験またはロボット合成を実行する関数
        feature_dim : int
            特徴量の次元数
        bounds : np.ndarray
            探索空間の境界 (feature_dim x 2)
        """
        self.experiment_function = experiment_function
        self.feature_dim = feature_dim
        self.bounds = bounds
        self.gp_model = None
        self.database = []
        self.iteration_count = 0

    def initialize(self, n_init: int = 5):
        """ランダムサンプリングで初期化"""
        print("=" * 70)
        print("Closed-Loop System Initialization")
        print("=" * 70)

        X_init = np.random.uniform(
            self.bounds[:, 0],
            self.bounds[:, 1],
            size=(n_init, self.feature_dim)
        )

        for i, x in enumerate(X_init):
            y = self.experiment_function(x)
            self.database.append({
                'iteration': 0,
                'timestamp': datetime.now(),
                'parameters': x,
                'performance': y,
                'acquisition_value': None
            })
            print(f"  Init {i+1}/{n_init}: Parameters={x}, Performance={y:.3f}")

        # 初期GPモデル学習
        self._update_model()
        print(f"\nInitialization complete: {len(self.database)} experiments\n")

    def _update_model(self):
        """GPモデルを最新データで更新"""
        X = np.array([d['parameters'] for d in self.database])
        y = np.array([d['performance'] for d in self.database])

        kernel = ConstantKernel(1.0) * RBF(length_scale=1.0)
        self.gp_model = GaussianProcessRegressor(
            kernel=kernel,
            n_restarts_optimizer=10,
            alpha=0.1,
            normalize_y=True
        )
        self.gp_model.fit(X, y)

    def acquisition_function(self, X: np.ndarray, beta: float = 2.0) -> np.ndarray:
        """Upper Confidence Bound獲得関数"""
        mu, sigma = self.gp_model.predict(X.reshape(1, -1), return_std=True)
        return mu + beta * sigma

    def propose_next_experiment(self, n_candidates: int = 100) -> Dict:
        """次の実験条件を提案"""
        # ランダムサンプリングで候補生成
        candidates = np.random.uniform(
            self.bounds[:, 0],
            self.bounds[:, 1],
            size=(n_candidates, self.feature_dim)
        )

        # 獲得関数を評価
        acq_values = np.array([
            self.acquisition_function(x) for x in candidates
        ]).flatten()

        # 最大値を選択
        best_idx = np.argmax(acq_values)
        best_candidate = candidates[best_idx]
        best_acq_value = acq_values[best_idx]

        return {
            'parameters': best_candidate,
            'acquisition_value': best_acq_value
        }

    def execute_experiment(self, parameters: np.ndarray) -> float:
        """実験実行(ロボットまたは計算)"""
        print(f"  [Robot] Preparing experiment with parameters: {parameters}")
        time.sleep(0.1)  # ロボット動作をシミュレート

        performance = self.experiment_function(parameters)

        print(f"  [Sensor] Measured performance: {performance:.3f}")
        return performance

    def run_iteration(self):
        """Active Learningの1イテレーション実行"""
        self.iteration_count += 1

        print("=" * 70)
        print(f"Iteration {self.iteration_count}")
        print("=" * 70)

        # 1. 候補提案(Active Learning)
        print("[Step 1] Active Learning: Proposing next experiment")
        proposal = self.propose_next_experiment()

        print(f"  Proposed parameters: {proposal['parameters']}")
        print(f"  Acquisition value: {proposal['acquisition_value']:.3f}")

        # 2. 実験実行(ロボット)
        print("\n[Step 2] Robot: Executing experiment")
        performance = self.execute_experiment(proposal['parameters'])

        # 3. データ蓄積(データベース)
        print("\n[Step 3] Database: Storing results")
        self.database.append({
            'iteration': self.iteration_count,
            'timestamp': datetime.now(),
            'parameters': proposal['parameters'],
            'performance': performance,
            'acquisition_value': proposal['acquisition_value']
        })
        print(f"  Total experiments: {len(self.database)}")

        # 4. モデル更新(機械学習)
        print("\n[Step 4] Machine Learning: Updating model")
        self._update_model()
        print("  Model updated with new data")

        # 5. 性能評価
        best_performance = max([d['performance'] for d in self.database])
        best_idx = np.argmax([d['performance'] for d in self.database])
        best_params = self.database[best_idx]['parameters']

        print("\n[Step 5] Evaluation:")
        print(f"  Current best performance: {best_performance:.3f}")
        print(f"  Best parameters: {best_params}")
        print()

        return performance

    def run_closed_loop(self, n_iterations: int = 10, target_performance: float = None):
        """クローズドループ最適化を実行"""
        print("\n" + "=" * 70)
        print("Starting Closed-Loop Optimization")
        print("=" * 70)
        print(f"Target iterations: {n_iterations}")
        if target_performance:
            print(f"Target performance: {target_performance}")
        print()

        for i in range(n_iterations):
            performance = self.run_iteration()

            # 早期終了判定
            if target_performance and performance >= target_performance:
                print("=" * 70)
                print(f"Target performance achieved in {i+1} iterations!")
                print("=" * 70)
                break

        self.summarize_results()

    def summarize_results(self):
        """最終結果のサマリー"""
        df = pd.DataFrame(self.database)

        print("\n" + "=" * 70)
        print("Closed-Loop Optimization Summary")
        print("=" * 70)

        print(f"\nTotal experiments: {len(self.database)}")
        print(f"Total iterations: {self.iteration_count}")

        best_idx = df['performance'].idxmax()
        best_result = df.loc[best_idx]

        print(f"\nBest Performance: {best_result['performance']:.3f}")
        print(f"Best Parameters: {best_result['parameters']}")
        print(f"Found at iteration: {best_result['iteration']}")

        # 学習曲線
        print("\nLearning Curve (Best Performance Over Time):")
        cumulative_best = df['performance'].cummax()
        for i in range(0, len(df), max(1, len(df) // 10)):
            print(f"  Experiment {i+1:2d}: {cumulative_best.iloc[i]:.3f}")


# 実験関数の定義(実際はロボット合成・測定)
def battery_capacity_experiment(parameters: np.ndarray) -> float:
    """
    バッテリー容量測定の仮想実験

    Parameters
    ----------
    parameters : np.ndarray
        [温度, 充電レート, 電解質濃度]

    Returns
    -------
    capacity : float
        容量 (mAh/g)
    """
    temp, rate, concentration = parameters

    # 仮想的な性能関数
    capacity = (
        200.0
        + 30 * np.sin(temp / 10)
        - 50 * (rate - 0.5) ** 2
        + 20 * np.exp(-((concentration - 1.0) ** 2))
        + np.random.normal(0, 5)  # 測定ノイズ
    )

    return max(0, capacity)


# 使用例: バッテリー材料の自律最適化
if __name__ == "__main__":
    # 探索空間の定義
    # [温度(℃), 充電レート(C), 電解質濃度(M)]
    bounds = np.array([
        [20.0, 60.0],   # 温度: 20-60℃
        [0.1, 1.0],     # 充電レート: 0.1-1.0C
        [0.5, 2.0]      # 濃度: 0.5-2.0M
    ])

    # クローズドループシステム構築
    system = ClosedLoopSystem(
        experiment_function=battery_capacity_experiment,
        feature_dim=3,
        bounds=bounds
    )

    # 初期化(ランダムサンプリング)
    system.initialize(n_init=5)

    # クローズドループ最適化実行
    system.run_closed_loop(
        n_iterations=10,
        target_performance=240.0  # 目標容量
    )

出力例:

======================================================================
Closed-Loop System Initialization
======================================================================
  Init 1/5: Parameters=[45.2 0.62 1.34], Performance=218.456
  Init 2/5: Parameters=[28.7 0.41 0.89], Performance=195.234
  Init 3/5: Parameters=[52.1 0.73 1.67], Performance=207.891
  Init 4/5: Parameters=[35.6 0.28 1.12], Performance=212.678
  Init 5/5: Parameters=[41.3 0.55 1.45], Performance=221.345

Initialization complete: 5 experiments

======================================================================
Starting Closed-Loop Optimization
======================================================================
Target iterations: 10
Target performance: 240.0

======================================================================
Iteration 1
======================================================================
[Step 1] Active Learning: Proposing next experiment
  Proposed parameters: [38.4 0.49 1.02]
  Acquisition value: 1.823

[Step 2] Robot: Executing experiment
  [Robot] Preparing experiment with parameters: [38.4 0.49 1.02]
  [Sensor] Measured performance: 228.712

[Step 3] Database: Storing results
  Total experiments: 6

[Step 4] Machine Learning: Updating model
  Model updated with new data

[Step 5] Evaluation:
  Current best performance: 228.712
  Best parameters: [38.4 0.49 1.02]

======================================================================
Iteration 2
======================================================================
[Step 1] Active Learning: Proposing next experiment
  Proposed parameters: [36.2 0.51 0.98]
  Acquisition value: 2.145

[Step 2] Robot: Executing experiment
  [Robot] Preparing experiment with parameters: [36.2 0.51 0.98]
  [Sensor] Measured performance: 241.234

[Step 3] Database: Storing results
  Total experiments: 7

[Step 4] Machine Learning: Updating model
  Model updated with new data

[Step 5] Evaluation:
  Current best performance: 241.234
  Best parameters: [36.2 0.51 0.98]

======================================================================
Target performance achieved in 2 iterations!
======================================================================

======================================================================
Closed-Loop Optimization Summary
======================================================================

Total experiments: 7
Total iterations: 2

Best Performance: 241.234
Best Parameters: [36.2 0.51 0.98]
Found at iteration: 2

Learning Curve (Best Performance Over Time):
  Experiment  1: 218.456
  Experiment  7: 241.234

4.4 実世界応用とキャリアパス

産業応用事例

Case Study 1: トヨタ - 触媒開発

課題: 排ガス浄化触媒の最適化 手法: Active Learning + 高スループット実験 結果: - 実験回数80%削減(1,000回 → 200回) - 開発期間2年 → 6ヶ月 - 触媒性能20%向上

Case Study 2: MIT - バッテリー材料

課題: Li-ion電池電解質の探索 手法: Active Learning + ロボット合成 結果: - 開発速度10倍向上 - 候補材料10,000種 → 50実験で最適解 - イオン伝導度30%向上

Case Study 3: BASF - プロセス最適化

課題: 化学プロセス条件の最適化 手法: Active Learning + シミュレーション 結果: - 年間3,000万ユーロのコスト削減 - プロセス効率15%向上 - 環境負荷20%削減

Case Study 4: Citrine Informatics

企業概要: Active Learning専門スタートアップ 顧客: 50社以上(化学、材料、製薬) サービス: - Active Learningプラットフォーム - データ分析コンサルティング - 自動実験システム統合

Case Study 5: Berkeley Lab - A-Lab

プロジェクト: 無人材料合成ラボ 実績: - 17日間で41種類の新材料合成 - 24時間365日稼働 - Active Learningで次の合成候補を自動提案

キャリアパス

Active Learning Engineer - 年収: 800万〜1,500万円 - 必要スキル: Python、機械学習、材料科学 - 主な雇用主: 素材メーカー、製薬、化学

Research Scientist(AL専門) - 年収: 1,000万〜2,000万円 - 必要スキル: 博士号、論文実績、プログラミング - 主な雇用主: 大学、研究機関、R&D部門

Automation Engineer - 年収: 900万〜1,800万円 - 必要スキル: ロボティクス、AL、システム統合 - 主な雇用主: 自動化スタートアップ、大手メーカー


本章のまとめ

学んだこと

  1. ベイズ最適化との統合 - BoTorchによる実装 - 連続空間 vs 離散空間

  2. 高スループット計算 - DFT計算の効率化 - Batch Active Learning

  3. 実験ロボット連携 - クローズドループ最適化 - 自律実験システム

  4. 産業応用 - 5つの成功事例 - 実験回数50-80%削減 - 開発期間大幅短縮

  5. キャリア機会 - AL Engineer、Research Scientist - 年収800万〜2,000万円 - 需要急増中

シリーズ完了

おめでとうございます!Active Learning入門シリーズを完了しました。

次のステップ: 1. ✅ 独自プロジェクトに挑戦 2. ✅ GitHubにポートフォリオ作成 3. ✅ ロボティクス実験自動化入門へ 4. ✅ 研究コミュニティに参加 5. ✅ 産業界でのキャリアを検討

シリーズ目次に戻る


演習問題

(省略:演習問題の詳細実装)


参考文献

  1. Kusne, A. G. et al. (2020). "On-the-fly closed-loop materials discovery via Bayesian active learning." Nature Communications, 11(1), 5966.

  2. MacLeod, B. P. et al. (2020). "Self-driving laboratory for accelerated discovery of thin-film materials." Science Advances, 6(20), eaaz8867.

  3. Stein, H. S. et al. (2019). "Progress and prospects for accelerating materials science with automated and autonomous workflows." Chemical Science, 10(42), 9640-9649.


ナビゲーション

前の章

← 第3章:獲得関数設計

シリーズ目次

← シリーズ目次に戻る


シリーズ完了!次はロボティクス実験自動化へ!

免責事項