如何使用 Scipy 拟合从 C++ 模型生成的数据?

计算科学 Python C++ scipy 库达
2021-12-03 09:27:54

我目前有一个用 C++ 和 CUDA 编写的功能强大且速度极快的模型。但是,我想使用 Scipy.minimize 使模型适合一些实验数据。我希望这很容易,但是当我尝试向 Google 描述我的问题时,它一直告诉我我想用 C++ 扩展 Python,它的文档让我想哭。

我过去曾经使用 PyCUDA,但我认为我无法包装整个模型,所以我需要在正确的方向上稍微推动一下。

我正在努力完成的事情。

from scipy.optimize import minimize
import os

#Initial starting parameters
ics = [ 1, 0, 0 ... 0]

#The objective function is called from my model, which is a built .exe that will accept parameters as maybe a string and somehow output something
model = os.popen("directory/mymodel.exe" + params)

difference = minimize(model, ics, method='Nelder-Mead')

这样的事情可能吗?我很难绕过 C++ 和 Python 之间的接口,以及如何使我的 .exe 生成可由 python 解释的数据,以便 Scipy 可以调整参数和迭代。

1个回答

其他评论建议使用基于文件的接口,使用实际的 C/C++ 优化库,或使用 C++ 扩展 Python。这些可能是解决问题的更好方法,但这里有一个更狭隘的答案。

首先,这是一个名为 mymodel.c 的 C 程序,它实现了 2d Rosenbrock 函数。


#include "stdio.h"
#include "assert.h"
#include "stdlib.h"

/* minimum is at (a, a*a) = (0.123, 0.015129) */
double rosenbrock_2d(double x, double y) {
  const double a = 0.123;
  const double b = 100.0;
  double u, v;
  u = a - x;
  v = y - x*x;
  return u*u + b*v*v;
}

int main(int argc, char **argv)
{
  double x, y;
  assert(argc == 3);
  x = atof(argv[1]);
  y = atof(argv[2]);
  printf("%.16g\n", rosenbrock_2d(x, y));
  return 0;
}

您可以使用类似以下命令的内容来构建它。


$ gcc -o mymodel.exe mymodel.c

这是一个名为 opt.py 的 python 脚本,它重复调用实现模型的可执行文件,同时尝试找到函数的最小值。


from scipy.optimize import minimize
import subprocess

#Initial starting parameters
ics = [ 1, 0]

#The objective function is called from my model, which is a built .exe that will accept parameters as maybe a string and somehow output something
def model(x):
    params = ['%.16g' % a for a in x]
    s = subprocess.check_output(['./mymodel.exe'] + params)
    return float(s)

print minimize(model, ics, method='Nelder-Mead')

然后运行它:

$ python opt.py                            
  状态:0
    nfev: 86
 成功:真
     乐趣:2.2359521022451379e-09
       x:数组([0.12296347,0.01512302])
 消息:“优化成功终止。”
     尼特:46

这给出了接近答案的东西。如果您想要更接近的答案,您可以使用不同的公差或更好的方法,例如“L-BFGS-B”。