张量在sympy?

时间:2019-03-28 18:01:57

标签: python computer-vision sympy

我想使用sympy来构建可调用的cython,以评估损失/雅各比/黑塞州。损失函数(由于缺少SO上的乳胶而定义为python函数)如下

def loss(omega, tau, x, w):
    # omega: [j, 3, 3] a stack of rotations
    # tau  : [j, 3]    a stack of translations
    # x    : [i, j, 3] a matrix of 3d image points
    # w    : [i ,3]    a stack of corresponding 3d world points
    total_loss = 0.
    for a in range(x.shape[0]):
        for b in range(x.shape[1]):
            z = np.matmul(omega[b], w[a]) + tau[b]
            z /= np.linalg.norm(z)
            total_loss += np.dot(x[a, b], z)
    return total_loss

这是来自动纸的https://itportal.ogauthority.co.uk/information/well_data/lithostratigraphy_hierarchy/rptLithoStrat_1Page2.html

仅考虑单个点并按如下方式转换i=j=时,我可以在sypy中构建适当的函数:

def name_sym(s, r, c):
    return s + '_' + str(r) + str(c)

def get_matrix_symbols(s, r, c):
    mat = []
    for i in range(r):
        mat.append([])
        for j in range(c):
            sym = sp.Symbol(name_sym(s, i, j), real=True)
            mat[i].append(sym)
    return mat

def get_matrix(s, r, c):
    mat = get_matrix_symbols(s, r, c)
    return sp.Matrix(mat)

omega = get_matrix('omega', 3, 3)
tau = get_matrix('tau', 3, 1)
w = get_matrix('w', 3, 1)
x = get_matrix('x', 3, 1)
z = omega*w + tau
z = z/z.norm()
reprojection_error = z.T * x
relavent_vars = sp.flatten(omega) + sp.flatten(tau) + sp.flatten(w)
jacobian = reprojection_error.jacobian(relavent_vars), reprojection_error
f = autowrap(jacobian, backend='cython')

def c_loss(omega, tau, w, x):
    inputs = np.concatenate([omega.ravel(), tau.ravel(), w.ravel(), x.ravel()])
    return f(*inputs)

但是我希望能够构建一个函数来实现ij的可变数量。除了使用IndexedBase sympy对象的最基本示例之外,我似乎什么也没做。如何使用IndexedBase对象来构建适当的表达式?

1 个答案:

答案 0 :(得分:0)

我最终放弃了Sympy,因为它麻烦多于其价值。如果您想进行一些自动微分,我建议您使用tensorflow,这是我最终要做的。下面是创建等式(7)的粗麻布的脚本。

import tensorflow as tf
from tensorflow.python.ops.parallel_for.gradients import jacobian


def flatten_and_order_variables(omega, tau, w):
    flattened_variables = tf.concat(
        [tf.reshape(w, [-1]),
         tf.reshape(omega, [-1]),
         tf.reshape(tau, [-1])],
        axis=0)

    flattened_variables = tf.Variable(flattened_variables)
    return flattened_variables


def build_graph(cameras, points):
    graph = tf.Graph()
    with graph.as_default():

        # inputs
        x = tf.placeholder(tf.float32, [cameras, points, 3], 'x')
        omega = tf.placeholder(tf.float32, [cameras, 3, 3], 'omega')
        tau = tf.placeholder(tf.float32, [cameras, 3], 'tau')
        w = tf.placeholder(tf.float32, [points, 3], 'w')
        camera_params = tf.concat([omega, tau[:, :, None]], axis=2)
        flat_inputs = tf.concat([tf.reshape(camera_params, [-1]), tf.reshape(w, [-1])], axis=0)

        flat_variables = tf.Variable(tf.zeros([cameras*12 + 3*points], tf.float32))
        assign = flat_variables.assign(flat_inputs)

        with tf.control_dependencies([assign]):
            camera_params = tf.reshape(flat_variables[:cameras*12], [cameras, 3, 4])
            omega_var = camera_params[:, :, :3]
            tau_var = camera_params[:, :, -1]
            w_var = tf.reshape(flat_variables[cameras*12:], [points, 3])

            # define loss
            z = tf.einsum('jab,ib->jia', omega_var, w_var) + tau_var[:, None]
            z = z / tf.linalg.norm(z, axis=2, keepdims=True)
            loss = tf.reduce_sum(x*z)

            # get jacobi
            jac = jacobian(loss, flat_variables)
            hess = jacobian(jac, flat_variables)
            tf.identity(loss, 'loss')
            tf.identity(hess, 'hessian')
            tf.identity(jac, 'jacobian')
    return graph


def build_feed_dict(graph, omega, tau, w, x):
    omega_p = graph.get_tensor_by_name('omega:0')
    tau_p = graph.get_tensor_by_name('tau:0')
    w_p = graph.get_tensor_by_name('w:0')
    x_p = graph.get_tensor_by_name('x:0')
    return {
        omega_p: omega,
        tau_p: tau,
        w_p: w,
        x_p: x
    }


def get_outputs(graph):
    loss = graph.get_tensor_by_name('loss:0')
    jac = graph.get_tensor_by_name('jacobian:0')
    hessian = graph.get_tensor_by_name('hessian:0')
    return loss, hessian, jac


def get_hessian(graph, omega, tau, w, x):
    with tf.Session(graph=graph) as sess:
        sess.run(tf.global_variables_initializer())
        feed_dict = build_feed_dict(graph, omega, tau, w, x)
        loss, hess, jac = get_outputs(graph)
        net_out = sess.run([loss, hess, jac], feed_dict)
    return net_out