我有一个非线性前向模型,它计算每个像素参数 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 实现 ,但它有它自己的问题。或者使用 Googles JAX LM 实现 ,但到目前为止我还没有使用 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]
i,j
如果我能让这个更快,多个图像也不会那么难实现,因为我只需要为参数提供一个数组。
If I could make this faster, multiple images wouldn't be that hard to implement too, since I only have to provide an array to the parameters.
你可以通过向量化最小化问题来加速代码,而不是为每个像素单独解决它。这使得可以同时为所有像素执行计算,这在像 NumPy 这样的库中可以高效完成。
以下是如何执行此操作:
-
向量化模型: 将模型修改为对
n
的数组(在本例中为所有像素的数组)进行操作,而不是单个值。模型应返回一个与输入n
大小相同的残差数组。 -
准备输入数据: 为所有像素创建一个
n
值的 2D 数组。 -
使用
least_squares
进行优化: 将n
的 2D 数组传递给least_squares
函数。该函数将找到使所有像素的残差之和最小化的a
、b
和c
的值。
以下是如何使用示例代码实现此操作:
import numpy as np
from scipy.optimize import least_squares
def my_model(n, a, b, c, img):
return a * n**2 + b * n + c - img
# 加载 img1、a1、b1、c1
# ...
# 创建所有像素的 n 值的 2D 数组
rows, cols = img1.shape
n_vals = np.arange(rows * cols).reshape(rows, cols)
# 向量化优化
def vectorized_model(x, n, img):
a, b, c = x
return my_model(n, a, b, c, img).ravel()
x0 = [1/3, 1/3, 1/3] # 初始猜测值 a、b、c
res = least_squares(vectorized_model, x0, args=(n_vals, img1))
# 获取优化的参数
a_opt, b_opt, c_opt = res.x
# 使用优化的参数计算 n 的值
n_opt = my_model(n_vals, a_opt, b_opt, c_opt, img1)
# 将 n_opt 重塑为 img1 的形状
n_opt = n_opt.reshape(rows, cols)
此代码片段首先定义了一个向量化版本的模型
vectorized_model
,该模型采用参数
x
(包含
a
、
b
、
c
)、
n
值的数组和图像作为输入。它返回一个包含所有像素的残差的扁平数组。然后,代码创建一个 2D 数组
n_vals
,其中包含所有像素的
n
值。
least_squares
函数用于找到使所有像素的残差之和最小化的最优参数
a_opt
、
b_opt
和
c_opt
。
这种向量化方法应比为每个像素单独执行优化快得多。
对于多幅图像,可以将
img
和相应的
n
值堆叠在一起,并相应地调整
vectorized_model
以处理附加维度。然后,
least_squares
优化将找到使所有图像和所有像素的总体残差最小的参数。