我想使用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
仅考虑单个点并按如下方式转换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)
但是我希望能够构建一个函数来实现i
和j
的可变数量。除了使用IndexedBase
sympy对象的最基本示例之外,我似乎什么也没做。如何使用IndexedBase
对象来构建适当的表达式?
答案 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