SISSO 与 pysisso

1. SISSO

SISSO 的全称是 Sure Independence Screening and Sparsifying Operator
你可以先把它粗略理解成一种“从很多候选特征和运算组合里,自动找出少数几个最有解释力描述符”的方法。

它特别吸引人的地方在于两点:

  • 它不是单纯做黑箱预测,而是会给出比较紧凑、可解释的表达式
  • 它很适合材料科学里那种“我不只想拟合,还想知道到底什么量在起作用”的问题

所以如果你的目标是:

  • 做可解释描述符构建
  • 从一堆候选物理量里筛选关键组合
  • 得到可以写进论文里的紧凑公式

SISSO 就很值得了

2. SISSO的编译

官方仓库:

一个典型流程大概是:

bash
git clone https://github.com/rouyang2017/SISSO.git
cd SISSO/src
mkdir -p ~/bin
mpiifort -fp-model precise var_global.f90 libsisso.f90 DI.f90 FC.f90 FCse.f90 SISSO.f90 -o ~/bin/SISSO
export PATH="$HOME/bin:$PATH"
which SISSO

这里最关键的是:

  • 你要有可用的 Fortran MPI 编译器
  • 最后真的生成了 SISSO 可执行文件
  • 并且 which SISSO 能找到它

不同服务器上编译器名字可能不一样。常见的有:

  • mpifort
  • mpiifort
  • mpif90

编译问题直接问 LLM。

SISSO 传统的使用方式,其实比较“经典 HPC”:

  • 先准备数据
  • 再写 SISSO.in
  • 编译官方 Fortran 程序
  • 在 Linux 服务器上运行
  • 最后自己检查输出文件

也就是说,它首先是一个外部可执行程序,跟 VASP 有点像,所以跟其他机器学习算法基于 python 使用差别比较大。 此前已经有 pysissoSISSO 进行包装,可以像 scikit-learn 一样使用。但是由于 SISSO 更新,已经无法使用,这里我更新了官方的代码,使其可以支持最新的 SISSO.

3. pysisso

pysisso 是一个 Python 包装层:

  • pysisso: https://github.com/Migie-cphy/pysisso
  • 底层真正执行的是官方 SISSO 3.5
  • 它本身不自带 SISSO 源码
  • 它做的事情,是把 SISSO 包装成更接近 scikit-learn 的接口

pysisso 的意义在于:以后你可以更自然地把 SISSO 接进 Python 工作流。

4. 安装 pysisso

准备好 Python 环境以后,安装 pysisso 就比较直接了。

例如用 conda:

bash
conda create -n pysisso python=3.11 -y
conda activate pysisso

然后安装:

bash
git clone git@github.com:Migie-cphy/pysisso.git
cd pysisso
pip install -e .

这里用 pip install -e . 的好处是你后面如果继续改代码、修 wrapper、加测试,都会比较方便。

5. pysisso 测试

这里用 scikit-learn 的糖尿病回归数据作为测试。

python
from pathlib import Path
import shutil

import numpy as np
import pandas as pd
from sklearn.datasets import load_diabetes
from sklearn.metrics import mean_absolute_error, r2_score
from sklearn.model_selection import train_test_split

from pysisso import SISSORegressor

sisso = shutil.which("SISSO")
if sisso is None:
    raise RuntimeError('SISSO executable not found. Run: export PATH="$HOME/bin:$PATH"')

data = load_diabetes(as_frame=True)
X = data.data[["bmi", "s5", "bp", "s1"]]
y = data.target

X_train, X_test, y_train, y_test = train_test_split(
    X.iloc[:120],
    y.iloc[:120],
    test_size=0.25,
    random_state=0,
)

run_dir = Path("sisso_diabetes_run")
model = SISSORegressor(
    desc_dim=2,
    ops="(+)(-)(*)(/)(^2)(sqrt)(log)",
    fcomplexity=2,
    nf_sis=50,
    nmodel=20,
    work_dir=str(run_dir),
    keep_work_dir=True,
    executable=sisso,
    timeout=300,
)

model.fit(X_train, y_train)
pred = model.predict(X_test)

print("SISSO executable:", sisso)
print("work_dir:", model.work_dir_)
print("descriptors:", [str(d) for d in model.descriptors_])
print("coef:", model.coef_)
print("intercept:", model.intercept_)
print("R2:", r2_score(y_test, pred))
print("MAE:", mean_absolute_error(y_test, pred))
print(pd.DataFrame({"y_true": y_test.to_numpy(), "y_pred": pred}).head(10))

assert np.all(np.isfinite(pred))
assert len(pred) == len(y_test)
assert (run_dir / "SISSO.in").exists()
assert (run_dir / "train.dat").exists()
assert (run_dir / "SISSO.out").exists()

输出:

text
descriptors: ['((bmi+s5)+s5)', '((bmi/bp)/s5)']
R2: 0.2855214500212161
MAE: 35.647991606637675
pysisso sklearn diabetes test passed.

如果正常输出没有报错,你就可以替换自己的数据进行使用了。