Используйте scipy.optimize.root для массива с дополнительными аргументами - PullRequest
0 голосов
/ 11 июня 2019

Учитывая задачу оптимизации (1), как показано ниже, где p_i, p'_i и w_ji даны для i=0,...,6889, я хочу использовать метод Левенберга-Марквардта, чтобы найти оптимальное решение для R_jи v_j с использованием scipy.optimize.root (я открыт для любых других предложений).

Imgur

Однако я не знаю, как настроить вызываемую функцию, которая требуетбыть переданным в 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

РЕДАКТИРОВАТЬ: Теперь это правильный результат.

1 Ответ

1 голос
/ 11 июня 2019

Используйте свой оригинал 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)

теперь попробуйте использовать cost_function в roots

...