【问题标题】:Use scipy.optimize.root on a numpy array with additional arguments在带有附加参数的 numpy 数组上使用 scipy.optimize.root
【发布时间】:2019-06-11 09:17:47
【问题描述】:

鉴于优化问题 (1) 如下所示,其中i=0,...,6889 给出了p_ip'_iw_ji,我想使用 Levenberg-Marquardt 方法找到R_j 的最优解和v_j 使用scipy.optimize.root(我愿意接受任何其他建议)。

但是,我不知道如何设置需要传递给root 的可调用函数。到目前为止,我所拥有的只是这显然是错误的。

def fun(x, (old_points, new_points, weights, n_joints)):
    """
    :param x: variable to optimize. It is supposed to encapsulate R and v from (1)
    :param old_points: original vertex positions, (6890,3) numpy array
    :param new_points: transformed vertex positions, (6890,3) numpy array
    :param weights: weight matrix obtained from spectral clustering, (n_joints, 6890) numpy array
    :param n_joints: number of joints
    :return: non-linear cost function to find the root of
    """
    # Extract rotations and offsets
    R = np.array([(np.array(x[j * 15:j * 15 + 9]).reshape(3, 3)) for j in range(n_joints)])
    v = np.array([(np.array(x[j * 15 + 9:j * 15 + 12])) for j in range(n_joints)])

    # Use equation (1) for the non-linear pass.
    # R_j p_i
    Rp = np.einsum('jkl,il', x, old_points) # x shall replace R
    # w_ji (Rp_ij + v_j)
    wRpv = np.einsum('ji,ijk->ik', weights, Rp + x) # x shall replace v

    # Set up a non-linear cost function, then compute the squared norm.
    d = new_points - wRpv
    result = np.einsum('ik,ik', d, d)

    return result

编辑:现在这是正确的结果。

【问题讨论】:

  • 您要优化哪些x, old_points, new_points, weights, rv, n_joints?关闭其他人。
  • 我正在尝试优化x,因为我不知道如何将其纳入问题中。据我了解,(1)中的R_jv_jx,而代码中的rv是我最初的猜测。
  • 那么x是唯一的未知数?
  • 是的。另外,提前谢谢你!

标签: python optimization scipy levenberg-marquardt


【解决方案1】:

使用你原来的fun(但给它一个更好的名字)

def fun(x, (old_points, new_points, weights, n_joints)):
    """
    :param x: variable to optimize. It is supposed to encapsulate R and v from (1)
    :param old_points: original vertex positions, (6890,3) numpy array
    :param new_points: transformed vertex positions, (6890,3) numpy array
    :param weights: weight matrix obtained from spectral clustering, (n_joints, 6890) numpy array
    :param n_joints: number of joints
    :return: non-linear cost function to find the root of
    """
    # Extract rotations and offsets
    R = np.array([(np.array(x[j * 15:j * 15 + 9]).reshape(3, 3)) for j in range(n_joints)])
    v = np.array([(np.array(x[j * 15 + 9:j * 15 + 12])) for j in range(n_joints)])

    # Use equation (1) for the non-linear pass.
    # R_j p_i
    Rp = np.einsum('jkl,il', x, old_points) # x shall replace R
    # w_ji (Rp_ij + v_j)
    wRpv = np.einsum('ji,ijk->ik', weights, Rp + x) # x shall replace v

    # Set up a non-linear cost function, then compute the squared norm.
    d = new_points - wRpv
    result = np.einsum('ik,ik', d, d)

    return result

对其进行闭包,使其接受单个输入(您正在求解的变量):

old_points = ...
new_points = ...
weights = ...
rv = ...
n_joints = ...
def cont_function(x):
    return fun(x, old_points, new_points, weights, rv, n_joints)

现在尝试在roots 中使用cost_function

【讨论】:

  • 谢谢,但我不太明白这应该如何工作,因为您不在fun 中的任何地方使用x,而result 只是一个numpy 浮点数组?也许我没有很好地解释我的问题,因此我再次编辑了我的帖子以指出它。
  • @Rani 只需将 fun 替换为您的更新代码,cost_function 保持不变。
  • 我现在知道了,谢谢你的努力!我所要做的就是将rv 替换为x
  • 抱歉,我并没有真正阅读您的代码,所以我不确定 rv 和 x 等是什么。但原理只是创建一个闭包,以便您传递roots 一个接受单个变量的函数。如果您不想在 roots 之外创建 cots_function,您甚至可以使用 lambda 函数。
  • 您可以使用functools.partial (docs.python.org/3/library/functools.html#functools.partial),而不是定义新函数cost_function。 Partial 正是为此任务定义的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-21
  • 2014-06-26
  • 1970-01-01
  • 2014-10-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多