我有一个非线性前向模型,它计算每个像素参数w的灰度图像。我还可以使用 scipys 优化函数 反转模型。我目前遇到的唯一问题是图像的大小使得这个解决方案非常慢...比如 7% 的像素在 40 分钟内计算得很慢。我使用 for 循环遍历所有像素并按像素应用模型。我尝试过 least_squares、leastsq 和 root 函数,但它们都非常慢。我还实现了导数值,因为我听说通过提供雅可比矩阵可以更快,但无济于事。
我认为 leastsq 可能是解决方案,因为它的描述中有以下声明:
x = arg min(sum(func(y)**2,axis=0))
y
如果我将图像重塑为
1xn
,它应该沿着 axis=0
最小化。但不知何故,我最终得到了一个大小为 2 的数组作为我的输入参数y
,而且我无法调试它。
我特别关注最小二乘优化,因为将来,我想提供多个图像,这些图像应该由相同的参数生成w(其他参数不同)。
除了scipy之外,还有其他库可以为这个问题提供更优雅的方法吗?
我还计划尝试root 函数的 numba 实现,但它有它自己的问题。或者使用 Google 的 LM JAX 实现,但到目前为止我还没有 JAX 的实际经验...
编辑 这是我的问题的一个小例子: 假设我有一个模型定义为
f(n) = a*n**2 + b*n + c
,其中 f(n)
是每个像素的图像值 n
。对于不同的三元组(a,b,c)
我可以生成图像I=f(n)
。现在,我有一组具有不同参数 I1, I2, ...
的图像,但 (a1, b1, c1), (a2, b2, c2),...
在每个像素上并没有不同。最简单的情况是只有一张图像n
,并且我有参数
I1
,并且可以使用根方法或最小化器来计算所需的(a1, b1, c1)
:n
循环每个像素需要相当长的时间,并且我已经尝试仅使用一个和模块和整数除法来计算索引来减少双for循环
def my_model(n, a, b, c, img=0):
return a * n**2 + b * n + c - img
# load img1, a1, b1, c1 from a file
n = np.zeros_like(img1)
for i in range img1.shape[0]:
for j in range img1.shape[1]:
x0 = 1/3
args = {
"a": a1,
"b": b1,
"c": c1,
"img": img1[i,j],
}
res = least_squares(my_model, x0, kwargs=args)
n[i, j] = res.x[0]
。
如果我可以做得更快,多个图像也不会那么难实现,因为我只需要为参数提供一个数组。
加速最小二乘拟合的一个技巧是提供接近函数实际根的起始值。
如果图像的像素彼此相关,一种方法是获取解决上一个最小二乘问题得到的 n 值,并将其作为 x0 提供给下一次调用。我观察到由此加速了大约 10 倍。
另一种方法是尝试找到一种更快的方法来计算 f
-1(x)。您可以使用多种方法,但一种方法是在一堆点处评估 f(x),并拟合从 f(x) 到 x 的样条曲线。 如果您只转换一个像素,则需要更长的时间来拟合样条线,但优点是在进行多次评估时可以节省时间。
这是一个例子。我获取了您的代码,并将其与以下图像
测试模式一起使用。 (将此图像保存为同一目录中的grayscale.png以进行测试。) 然后我比较了两种方法:逐像素方法,以及将样条曲线拟合到函数反函数。我发现样条方法大约快 100 倍。
样条方法有两点好处:识别逆矩阵需要更少的计算,并且可以以矢量化方式完成更多计算。这大约快了 100 倍。
i,j