目錄

  1. 專案概述
  2. 基礎理論
  3. 系統架構
  4. 資料處理流程
  5. 模型架構詳解
  6. 訓練與預測流程
  7. 技術細節

專案概述

本專案是一個基於機器學習的化學性質預測系統,主要包含兩個子專案:

  1. ChemProp_VP - 基於圖神經網絡(GNN)的分子性質預測模型,專注於蒸氣壓(Vapor Pressure)預測
  2. 2025_COSMO - 基於 COSMO(Conductor-like Screening Model)σ-profile 的汽液平衡(VLE)預測系統

主要功能

  • 分子 3D 結構生成與優化
  • COSMO 量子化學計算
  • σ-profile 特徵提取
  • 深度學習模型訓練
  • 二元混合物相平衡預測

基礎理論

1. COSMO 理論

COSMO(Conductor-like Screening Model) 是一種連續溶劑化模型,用於計算分子表面的電荷分布。

核心概念:

  • σ-profile(表面電荷密度分佈):描述分子表面不同電荷密度區域的統計分佈
  • 表面片段(Surface Segments):將分子表面離散化為多個小片段,每個片段有其電荷密度 σ
  • 篩選電荷(Screening Charge):溶劑對溶質電荷的屏蔽效應

σ-profile 計算流程:

  1. 幾何優化:使用 DFT (B3LYP/6-31G(d,p)) 優化分子幾何結構
  2. COSMO 計算:生成分子表面的電荷分布(.cosmo 檔案)
  3. 平滑化處理σ_i = Σ_j (σ_0j × (r_j² × r_eff²) / (r_j² + r_eff²) × exp(-d_ij²/(r_j² + r_eff²)))

其中 r_eff = 7.5 Ų 為有效半徑 4. 分佈統計:統計 σ 在 [-0.025, 0.025] e/Ų 範圍內的分佈,生成 51 個 bin 的直方圖

2. 圖神經網絡(GNN)用於分子性質預測

Message Passing Neural Network (MPNN)

ChemProp 使用的核心架構,透過消息傳遞機制學習分子的圖表示:

  1. 節點特徵:原子類型、雜化、電荷、芳香性等
  2. 邊特徵:鍵類型、共軛性、環狀態等
  3. 消息傳遞m_v^(t+1) = Σ_(u∈N(v)) M_t(h_v^t, h_u^t, e_uv) h_v^(t+1) = U_t(h_v^t, m_v^(t+1))

特殊設計:

  • Atomic Fingerprint:可選擇輸出原子級別的表示,而非僅分子級別
  • Hybrid Method:結合分子級和原子級表示
  • Temperature Concatenation:將溫度作為額外特徵併入

3. 蒸氣壓經驗方程

模型支援多種蒸氣壓方程式:

Tu Equation

ln(P) = A + B/T - C×ln(T) - D×T

Antoine Equation

ln(P) = A - B/(C+T)

Riedel Equation

ln(P) = A - B/T + C×ln(T) + D×T^6

Wagner25 Equation

τ = 1 - T
ln(P) = A + (B×τ + C×τ^1.5 + D×τ^2.5 + E×τ^5)/T

系統架構

AI for Chemistry/
│
├── code/
│   ├── chemprop_VP-main/          # ChemProp 蒸氣壓預測模型
│   │   ├── chemprop/              # 核心套件
│   │   │   ├── models/            # 模型定義
│   │   │   │   ├── model.py       # MoleculeModel 主模型
│   │   │   │   ├── mpn.py         # Message Passing Network
│   │   │   │   └── equations.py   # 蒸氣壓方程式
│   │   │   ├── train/             # 訓練相關
│   │   │   ├── data/              # 資料處理
│   │   │   ├── features/          # 特徵生成
│   │   │   └── args.py            # 參數配置
│   │   ├── train.py               # 訓練入口
│   │   ├── predict.py             # 預測入口
│   │   └── environment.yml        # 環境配置
│   │
│   └── 2025_COSMO/                # COSMO VLE 預測系統
│       ├── mol_to_cosmo/          # 分子轉 COSMO
│       │   ├── name_to_mol.py     # CID → SMILES → 3D MOL
│       │   └── process_gjf.py     # MOL → GJF (Gaussian 輸入)
│       ├── data/                  # 資料與 σ-profiles
│       │   └── s-profiles-all/    # COSMO σ-profile 資料庫
│       │       └── cosmo_to_s_profile_ver_1.1.1.py
│       ├── grouping/              # 分組預測
│       │   ├── code/              # 分組模型程式
│       │   └── data/              # 訓練資料
│       └── model_train/           # MLP 模型訓練
│           ├── MLP_ln_V1_COSMO.ipynb
│           └── results_V1/        # 訓練結果(10-fold)
│
├── envs/                          # 環境配置檔
└── Ref/                           # 參考文獻

資料處理流程

階段一:分子結構生成(mol_to_cosmo)

1. name_to_mol.py - 分子結構生成

輸入:name.csv(包含 PubChem CID)
↓
PubChem API 查詢 → SMILES 字串
↓
RDKit 轉換:SMILES → 3D 分子結構
↓
幾何優化:Distance Geometry + UFF 力場
↓
輸出:mol/{CID}.mol 檔案

核心程式碼邏輯

# 1. 從 PubChem 獲取 SMILES
c = get_compounds(str(CID), 'cid')
sm = c[0].isomeric_smiles

# 2. SMILES 轉 3D 結構
mols_from_sm = MolFromSmiles(sm)
mh = AddHs(mols_from_sm)
EmbedMolecule(mh, useBasicKnowledge=True, useExpTorsionAnglePrefs=False)

# 3. UFF 優化
if UFFHasAllMoleculeParams(mh):
    UFFOptimizeMolecule(mh)

# 4. 儲存 MOL 檔
MolToMolFile(DG_UFF, f"./mol/{CID}.mol")

2. process_gjf.py - Gaussian 輸入檔生成

輸入:mol/{CID}.mol
↓
解析 MOL 檔中的原子座標
↓
生成兩步計算的 GJF 檔案:
  Step 1: 幾何優化 (opt b3lyp/6-31g(d,p))
  Step 2: COSMO 計算 (SCRF=COSMORS)
↓
輸出:gjf/{CID}.gjf

GJF 檔案結構

%chk={CID}-opt-b3lyp.chk
%mem=10GB
%NProcShared=12
# opt=(calcfc) b3lyp/6-31g(d,p) scf=tight

pe cosmo generation

0 1
[原子座標]

--Link1--
%chk={CID}-opt-b3lyp.chk
%mem=10GB
%NProcShared=12
# b3lyp/6-31g(d,p) geom=checkpoint guess=read scf=tight SCRF=(COSMORS)

pe cosmo generation

0 1

{CID}-opt-b3lyp.cosmo

階段二:σ-profile 提取

cosmo_to_s_profile_ver_1.1.1.py

輸入:{CID}.cosmo (Gaussian 輸出)
↓
解析 COSMO 檔案:
  - 表面片段數量 (nseg)
  - 片段座標 (x, y, z)
  - 原始電荷密度 (σ₀)
  - 片段面積 (area)
  - 總表面積、體積
↓
平滑化處理(加權平均):
  計算片段間距離矩陣 dmn²
  應用高斯核函數平滑
↓
統計分佈:
  在 [-0.025, 0.025] e/Ų 範圍
  劃分為 51 個 bin
  計算每個 bin 的總面積
↓
正規化:面積除以總表面積
↓
輸出:
  - s-profile/{CID}.csv (正規化的 σ-profile)
  - s-profile_area/{CID}.csv (含面積資訊)

關鍵計算

# 距離矩陣
dmn2[j][i] = (x[j] - x[i])² + (y[j] - y[i])² + (z[j] - z[i])²

# 平滑權重
aa = dmn2[j][i] / (rn[i]² + reff²)
susi[j][i] = 1 / exp(aa)

# 平滑後的電荷密度
σ[i] = Σ_j (σ₀[j] × (rn[j]² × reff²)/(rn[j]² + reff²) × susi[i][j]) / 
       Σ_j ((rn[j]² × reff²)/(rn[j]² + reff²) × susi[i][j])

階段三:特徵工程

train_gen_exp.ipynb - 訓練資料生成

輸入:
  - 實驗 VLE 資料(xA, yA, P, T)
  - 兩個組分的 σ-profile
↓
特徵組合:
  [σ-profile_A (51維)] + [σ-profile_B (51維)] + 
  [Area_A, Area_B, Volume_A, Volume_B] + 
  [Temperature, xA]
  = 108 維特徵向量
↓
目標變數:
  - yA (氣相莫耳分率)
  - P (總壓力,Pa → kPa 轉換)
↓
輸出:train_exp_data_F.csv

分組策略(grouping)

根據氫鍵特性將混合物分為 14 組:

  • COOH_COOH
  • COOH_HB-A (Hydrogen Bond Acceptor)
  • COOH_OH
  • HB-A_HB-A
  • NH_HB-A
  • NH_OH
  • Non-HB_COOH
  • Non-HB_HB-A
  • Non-HB_NH
  • Non-HB_Non-HB (最大組)
  • Non-HB_OH
  • OH_HB-A
  • OH_OH

分組依據

  • COOH:羧基(強氫鍵供體/受體)
  • OH:羥基(氫鍵供體/受體)
  • NH:胺基(氫鍵供體/受體)
  • HB-A:氫鍵受體(羰基、醚、酯等)
  • Non-HB:無氫鍵(烷烴、芳烴等)

模型架構詳解

1. ChemProp 模型(蒸氣壓預測)

MoleculeModel 類別結構

class MoleculeModel(nn.Module):
    def __init__(self, args):
        # 編碼器:Message Passing Network
        self.encoder = MPN(args)

        # 前饋網絡(可選多個)
        if args.Tconcat:  # 溫度串接模式
            self.ffn_A = self.create_ffn(args)
        else:  # 參數預測模式
            self.ffn_A = self.create_ffn(args)  # 預測 A
            self.ffn_B = self.create_ffn(args)  # 預測 B
            self.ffn_C = self.create_ffn(args)  # 預測 C
            self.ffn_D = self.create_ffn(args)  # 預測 D
            self.ffn_E = self.create_ffn(args)  # 預測 E

        # 方程式
        self.equation = get_equation(args)

MPNEncoder - 消息傳遞編碼器

輸入處理

# 原子特徵(133維)
atom_features = [
    atomic_number,      # 原子序
    degree,             # 連接度
    formal_charge,      # 形式電荷
    chiral_tag,         # 手性標籤
    num_Hs,             # 氫原子數
    hybridization,      # 雜化類型
    aromaticity,        # 芳香性
    atomic_mass         # 原子質量
]

# 鍵特徵(14維)
bond_features = [
    bond_type,          # 鍵類型
    conjugated,         # 共軛
    ring,               # 環狀
    stereo              # 立體化學
]

消息傳遞過程(depth 次迭代):

for depth in range(self.depth - 1):
    # 無向圖處理
    if self.undirected:
        message = (message + message[b2revb]) / 2

    # 聚合鄰居消息
    nei_a_message = index_select_ND(message, a2b)
    a_message = nei_a_message.sum(dim=1)

    # 更新消息
    rev_message = message[b2revb]
    message = a_message[b2a] - rev_message

    # 線性轉換 + 激活
    message = self.W_h(message)
    message = self.act_func(input + message)
    message = self.dropout_layer(message)

Readout 機制

# 原子級特徵聚合
for i, (a_start, a_size) in enumerate(a_scope):
    cur_hiddens = atom_hiddens.narrow(0, a_start, a_size)

    if self.fp_method == 'molecular':
        # 分子級:平均或求和
        mol_vec = cur_hiddens.sum(dim=0) / a_size

    elif self.fp_method == 'atomic':
        # 原子級:保留所有原子表示,zero-padding 至固定長度
        mol_vec = self.padding(cur_hiddens, padding_size=100)
        mol_mask = self.mask(cur_hiddens, padding_size=100)

    elif self.fp_method == 'hybrid_dim0':
        # 混合模式0:串接分子級和原子級
        mol_vec_molar = cur_hiddens.sum(dim=0) / a_size
        mol_vec = torch.cat((cur_hiddens, mol_vec_molar), dim=0)
        mol_vec = self.padding(mol_vec, padding_size=101)

    elif self.fp_method == 'hybrid_dim1':
        # 混合模式1:每個原子複製分子級特徵並串接
        mol_vec_molar = cur_hiddens.sum(dim=0) / a_size
        mol_vec_molar_ensemble = mol_vec_molar.repeat(a_size, 1)
        mol_vec = torch.cat((cur_hiddens, mol_vec_molar_ensemble), dim=1)
        mol_vec = self.padding(mol_vec, padding_size=100)

前向傳播邏輯

模式一:Tconcat(溫度串接)

if self.Tconcat:
    if self.fp_method == 'molecular':
        # 分子級:直接串接溫度
        hidden = torch.cat([hidden, T_batch], dim=1)
        output = self.ffn_A(hidden)

    else:
        # 原子級:每個原子都串接溫度
        temp_atomic = T_batch.repeat_interleave(n_atoms).unsqueeze(-1)
        hidden = torch.cat([hidden, temp_atomic], dim=2)

        # 應用 mask,聚合原子貢獻
        masked = hidden * mask
        ffn_output = self.ffn_A(masked)
        output = torch.sum(ffn_output, 1)

模式二:方程式參數預測

else:
    # 預測方程式的 5 個參數
    A = self.ffn_A(hidden)
    B = self.ffn_B(hidden)
    C = self.ffn_C(hidden)
    D = self.ffn_D(hidden)
    E = self.ffn_E(hidden)

    # 原子級需要聚合
    if self.fp_method in ['atomic', 'hybrid_dim0', 'hybrid_dim1']:
        A = torch.sum(A * mask, 1)
        B = torch.sum(B * mask, 1)
        C = torch.sum(C * mask, 1)
        D = torch.sum(D * mask, 1)
        E = torch.sum(E * mask, 1)

    # 應用方程式
    Pvap = self.equation(A, B, C, D, E, T_batch)
    output = Pvap.reshape(-1, 1)

    # Tu 方程式需要分子量校正
    if self.eqn_name == 'Tu':
        output = output - torch.log(self.encoder.MW())

2. COSMO-MLP 模型(VLE 預測)

模型架構(MLP_ln_V1_COSMO.ipynb)

超參數優化(Optuna):

def objective(trial):
    # 超參數空間
    n_layers = trial.suggest_int('n_layers', 2, 4)
    units = []
    for i in range(1, n_layers + 1):
        units.append(trial.suggest_int(f'units_layer_{i}', 64, 512))
    learning_rate = trial.suggest_float('learning_rate', 1e-5, 1e-2, log=True)
    batch_size = trial.suggest_categorical('batch_size', [32, 64, 128, 256])
    epochs = trial.suggest_int('epochs', 500, 2000)

    # 建立模型
    model = Sequential()
    model.add(Dense(units[0], activation='relu', input_dim=108))
    for i in range(1, n_layers):
        model.add(Dense(units[i], activation='relu'))
    model.add(Dense(2))  # yA 和 P

    # 編譯與訓練
    model.compile(optimizer=Adam(learning_rate), loss='mse')
    history = model.fit(X_train, y_train, 
                       validation_data=(X_val, y_val),
                       batch_size=batch_size,
                       epochs=epochs,
                       callbacks=[early_stopping],
                       verbose=0)

    # 評估指標(AAD-y 和 AARD-P 的組合)
    score = calculate_custom_metric(y_pred, y_val)
    return score

10-Fold 交叉驗證

kf = KFold(n_splits=10, shuffle=True, random_state=42)

for fold, (train_idx, val_idx) in enumerate(kf.split(X)):
    # 創建 Optuna study
    study = optuna.create_study(direction='minimize')
    study.optimize(objective, n_trials=200)

    # 取得最佳超參數
    best_params = study.best_params

    # 用最佳超參數重新訓練
    best_model = build_model(best_params)
    best_model.fit(X_train, y_train, ...)

    # 儲存模型
    best_model.save(f'fold_{fold+1}_model.h5')

    # 儲存超參數
    with open(f'fold_{fold+1}_best_trial.json', 'w') as f:
        json.dump(best_params, f)

最佳模型範例(fold_1):

{
  "trial": 93,
  "fold": 1,
  "param_count": 99914,
  "best_epoch": 1423,
  "train_loss": 0.005431,
  "val_loss": 0.006883,
  "score": 2.615,
  "params": {
    "n_layers": 2,
    "units": {
      "units_layer_1": 129,
      "units_layer_2": 236
    },
    "learning_rate": 0.000252,
    "batch_size": 64,
    "epochs": 1495
  }
}

資料正規化

MinMaxScaler 管道

from sklearn.preprocessing import MinMaxScaler
from sklearn.pipeline import Pipeline

# 創建 pipeline
pipeline = Pipeline([
    ('scaler', MinMaxScaler())
])

# 擬合訓練資料
pipeline.fit(X_train)

# 轉換
X_train_scaled = pipeline.transform(X_train)
X_val_scaled = pipeline.transform(X_val)

# 儲存 pipeline(用於預測時的一致性)
joblib.dump(pipeline, 'pipelineMLP_COSMO.joblib')

預測與反正規化

# 載入模型和 scaler
model = load_model('MLP_Vali_COSMO_1.h5')
pipeline = load('pipelineMLP_COSMO.joblib')
scaler = pipeline.named_steps['scaler']

# 預測(正規化空間)
y_pred_scaled = model.predict(X_test_scaled)

# 反正規化
scaler_maxy = scaler.data_max_[-2]  # yA 的最大值
scaler_maxp = scaler.data_max_[-1]  # P 的最大值
scaler_miny = scaler.data_min_[-2]  # yA 的最小值
scaler_minp = scaler.data_min_[-1]  # P 的最小值

yA_pred = y_pred_scaled[:, 0] * (scaler_maxy - scaler_miny) + scaler_miny
P_pred = y_pred_scaled[:, 1] * (scaler_maxp - scaler_minp) + scaler_minp

訓練與預測流程

ChemProp 訓練流程

1. 資料準備

# 資料格式:CSV
# smiles,target,temperature
# CCO,2.5,298.15
# c1ccccc1,3.2,300.00

2. 訓練命令

python train.py \
    --data_path data/train.csv \
    --dataset_type regression \
    --save_dir models/vp_model \
    --depth 3 \
    --hidden_size 300 \
    --ffn_num_layers 2 \
    --ffn_hidden_size 300 \
    --dropout 0.1 \
    --epochs 50 \
    --batch_size 50 \
    --fp_method molecular \
    --Tconcat \
    --num_folds 10

關鍵參數

  • --depth: MPNN 消息傳遞深度
  • --hidden_size: 隱藏層維度
  • --fp_method: 指紋方法(molecular/atomic/hybrid_dim0/hybrid_dim1)
  • --Tconcat: 溫度串接模式
  • --equation: 蒸氣壓方程式(Tu/Antonine/Riedel/Wagner25)
  • --num_folds: K-fold 交叉驗證

3. 預測

python predict.py \
    --test_path data/test.csv \
    --checkpoint_dir models/vp_model \
    --preds_path predictions.csv

COSMO-MLP 訓練流程

1. 完整工作流程

步驟 1: 分子結構生成
cd mol_to_cosmo
python name_to_mol.py
→ 生成 mol/{CID}.mol

步驟 2: Gaussian 輸入檔生成
python process_gjf.py
→ 生成 gjf/{CID}.gjf

步驟 3: Gaussian 計算(外部)
# 在 HPC 或本地運行 Gaussian
g09 {CID}.gjf
→ 生成 {CID}.cosmo

步驟 4: σ-profile 提取
cd data/s-profiles-all
python cosmo_to_s_profile_ver_1.1.1.py
→ 生成 s-profile/{CID}.csv

步驟 5: 訓練資料生成
cd data
jupyter notebook train_gen_exp.ipynb
→ 執行筆記本,生成 train_exp_data_F.csv

步驟 6: 模型訓練
cd model_train
jupyter notebook MLP_ln_V1_COSMO.ipynb
→ 執行筆記本,訓練 10-fold 模型

步驟 7: 分組預測
cd grouping/code
jupyter notebook grouping_COSMO_f.ipynb
→ 執行筆記本,按組別預測

2. 訓練邏輯(偽代碼)

# 讀取資料
data = pd.read_csv('train_exp_data_F.csv', header=None)
data.iloc[:, -1] = data.iloc[:, -1] / 1000  # Pa → kPa

# 特徵與標籤
X = data.iloc[:, :-2].values  # 108 維特徵
y = data.iloc[:, -2:].values  # [yA, P]

# 10-Fold 交叉驗證
kf = KFold(n_splits=10, shuffle=True, random_state=42)

for fold_idx, (train_idx, val_idx) in enumerate(kf.split(X)):
    print(f"Training Fold {fold_idx + 1}/10")

    # 分割資料
    X_train, X_val = X[train_idx], X[val_idx]
    y_train, y_val = y[train_idx], y[val_idx]

    # 正規化
    scaler = MinMaxScaler()
    X_train_scaled = scaler.fit_transform(X_train)
    X_val_scaled = scaler.transform(X_val)

    # Optuna 超參數優化
    study = optuna.create_study(direction='minimize')
    study.optimize(objective, n_trials=200)

    best_params = study.best_params

    # 用最佳參數重新訓練
    model = build_model(best_params)

    # TensorBoard 回調
    log_dir = f"logs/fold_{fold_idx+1}"
    tensorboard_callback = TensorBoard(log_dir=log_dir)

    # Early Stopping
    early_stop = EarlyStopping(
        monitor='val_loss',
        patience=100,
        restore_best_weights=True
    )

    # 訓練
    history = model.fit(
        X_train_scaled, y_train,
        validation_data=(X_val_scaled, y_val),
        epochs=best_params['epochs'],
        batch_size=best_params['batch_size'],
        callbacks=[tensorboard_callback, early_stop],
        verbose=1
    )

    # 儲存模型
    model.save(f'results_V1/model/h5/MLP_Vali_COSMO_{fold_idx+1}.h5')

    # 儲存超參數
    with open(f'results_V1/fold_{fold_idx+1}/fold_{fold_idx+1}_best_trial.json', 'w') as f:
        json.dump({
            'trial': study.best_trial.number,
            'fold': fold_idx + 1,
            'best_epoch': len(history.history['loss']),
            'train_loss': min(history.history['loss']),
            'val_loss': min(history.history['val_loss']),
            'score': study.best_value,
            'params': best_params
        }, f, indent=2)

3. 分組預測邏輯

# 載入最佳模型(選擇某一個 fold)
fold_idx = 1
model = load_model(f'model/h5/MLP_Vali_COSMO_{fold_idx}.h5')
pipeline = load('model/pipelineMLP_COSMO.joblib')

# 讀取分組資料
train_exp_final = pd.read_csv('data/train_exp_datapoint.csv')
train_group_all = pd.read_csv('data/train_group_all_V2.csv')

# 合併資料
merged_data = pd.merge(
    train_group_all, 
    train_exp_final, 
    on=['comp.A', 'comp.B', 'T'], 
    how='inner'
)

# 按 sheet_name(組別)分組
grouped = merged_data.groupby('sheet_name')

# 逐組預測
for sheet_name, group in grouped:
    print(f"Processing group: {sheet_name}")

    # 提取特徵
    X_group = group.iloc[:, feature_columns].values
    X_group_scaled = pipeline.transform(X_group)

    # 預測
    y_pred_scaled = model.predict(X_group_scaled)

    # 反正規化
    yA_pred = inverse_transform_yA(y_pred_scaled[:, 0])
    P_pred = inverse_transform_P(y_pred_scaled[:, 1])

    # 加入預測結果
    group['yA_pred'] = yA_pred
    group['P_pred'] = P_pred

    # 計算誤差
    group['AAD_y'] = abs(group['yA_exp'] - group['yA_pred'])
    group['AARD_P'] = abs(group['P_exp'] - group['P_pred']) / group['P_exp'] * 100

    # 儲存結果
    group.to_csv(f'grouping_COSMO/{sheet_name}.csv', index=False)

    # 統計
    mean_AAD_y = group['AAD_y'].mean()
    mean_AARD_P = group['AARD_P'].mean()
    print(f"  Mean AAD-y: {mean_AAD_y:.4f}")
    print(f"  Mean AARD-P: {mean_AARD_P:.2f}%\n")

技術細節

1. 資料格式

COSMO 檔案格式

Gaussian 09 SCRF=COSMORS output
...
area              =    XXX.XX
volume            =    XXX.XX
#
nseg  natom     x         y         z      charge   area    sigma0
   1      1   X.XXXX   Y.YYYY   Z.ZZZZ   Q.QQQQ  A.AAAA  S.SSSS
   2      1   X.XXXX   Y.YYYY   Z.ZZZZ   Q.QQQQ  A.AAAA  S.SSSS
   ...

σ-profile CSV 格式

sigma,probability
-0.025,0.0234
-0.024,0.0456
...
0.024,0.0123
0.025,0.0089
area,XXX.XX
volume,YYY.YY

訓練資料格式(train_exp_data_F.csv)

# 無標頭,108 維特徵 + 2 維目標
# 特徵:[σ-profile_A (51)] + [σ-profile_B (51)] + [Area_A, Area_B, Vol_A, Vol_B] + [T, xA]
# 目標:[yA, P]
0,0,...,0,4.58,3.64,...,199.93,0.0085,0.2602,65156
0,0,...,0,4.58,3.64,...,199.93,0.0291,0.5272,98596
...

2. 環境設置

ChemProp 環境

# environment.yml
name: chemprop
dependencies:
  - python=3.7
  - pytorch=1.9.0
  - rdkit
  - numpy
  - pandas
  - scikit-learn
  - tensorboardX
  - tqdm

安裝:

conda env create -f environment.yml
conda activate chemprop

COSMO-MLP 環境

# tf_py313.yml
name: tf_py313
dependencies:
  - python=3.13
  - pip
  - pip:
    - tensorflow==2.20.0
    - keras==3.13.0
    - keras-tuner==1.4.8
    - optuna==4.6.0
    - scikit-learn==1.8.0
    - pandas==2.3.3
    - numpy==2.4.0
    - matplotlib==3.10.8
    - seaborn==0.13.2
    - rdkit==2025.9.3
    - joblib==1.5.3

安裝:

conda env create -f envs/tf_py313.yml
conda activate tf_py313

3. 計算資源需求

Gaussian 計算

  • CPU: 12 核心推薦
  • 記憶體: 10 GB 每個任務
  • 時間: 視分子大小,10 分鐘 ~ 數小時
  • 硬碟: 每個分子約 50-200 MB

ChemProp 訓練

  • GPU: NVIDIA GPU(至少 4GB VRAM)
  • CPU: 8 核心推薦
  • 記憶體: 16 GB
  • 時間: 數小時(視資料量)

COSMO-MLP 訓練

  • GPU: NVIDIA GPU(建議 8GB+ VRAM)
  • CPU: 16 核心推薦
  • 記憶體: 32 GB
  • 時間: 每個 fold 約 4-12 小時(200 trials Optuna)

4. 性能指標

評估指標

AAD-y(Average Absolute Deviation in vapor mole fraction)

AAD-y = (1/N) × Σ |y_exp - y_pred|

目標:< 0.02 (2%)

AARD-P(Average Absolute Relative Deviation in pressure)

AARD-P = (1/N) × Σ |(P_exp - P_pred) / P_exp| × 100%

目標:< 5%

報告性能(COSMO-MLP, fold_1):

  • AAD-y = 1.04%
  • AARD-P = 2.88%

5. 檔案路徑約定

ChemProp

checkpoint: models/{model_name}/fold_{i}/model.pt
predictions: predictions/{model_name}/fold_{i}/test_preds.csv
logs: logs/{model_name}/

COSMO-MLP

models: results_V1/model/h5/MLP_Vali_COSMO_{fold}.h5
pipeline: results_V1/model/pipelineMLP_COSMO.joblib
hyperparams: results_V1/fold_{i}/fold_{i}_best_trial_{trial}.json
logs: logs/fold_{i}/
predictions: grouping_COSMO/{group_name}.csv

附錄

A. 重要參數總表

ChemProp 參數

參數 預設值 說明
depth 3 MPNN 深度
hidden_size 300 隱藏層維度
ffn_num_layers 2 FFN 層數
ffn_hidden_size 300 FFN 隱藏層維度
dropout 0.0 Dropout 比率
activation ReLU 激活函數
fp_method molecular 指紋方法
aggregation mean 聚合方式
Tconcat False 溫度串接模式
equation None 蒸氣壓方程式

COSMO-MLP 參數(最佳)

參數 Fold 1 說明
n_layers 2 隱藏層數
units_layer_1 129 第一層單元數
units_layer_2 236 第二層單元數
learning_rate 0.000252 學習率
batch_size 64 批次大小
epochs 1495 訓練週期

B. 引用與參考

  1. ChemProp:
  • Yang, K., et al. "Analyzing Learned Molecular Representations for Property Prediction." Journal of Chemical Information and Modeling (2019). 2. COSMO-RS:

  • Klamt, A. "Conductor-like Screening Model for Real Solvents: A New Approach to the Quantitative Calculation of Solvation Phenomena." The Journal of Physical Chemistry (1995). 3. Message Passing Neural Networks:

  • Gilmer, J., et al. "Neural Message Passing for Quantum Chemistry." ICML (2017).


文件版本: 1.0 更新日期: 2026-02-12