Search code examples
theano

Elementwise updates of shared matrix in Theano


I am trying to calculate the gradient of the energy function, E( phi, theta, psi), where phi, theta, psi are Euler angles around Z, Y and X axis respectively. R is a rotation matrix converted from Euler angles. Where the columns are rotation vectors. For a point cloud of a indoor room, I have normals N for each point in the point cloud. N has shape of (numPoints x 3)

Now E = sum(1-max(N.dot(R))

I would like to find the gradient of E with respect to Euler angles.

To begin with the problem I am trying to calculate rotation matrix R from Euler angles using Theano. Please find the code below.

import theano
import theano.tensor as T
import numpy as np

phi = theano.shared(value=np.pi/3, name='phi')
theta = theano.shared(value=np.pi/3, name='theta')
psi = theano.shared(value=np.pi/3, name='psi')

# phi = T.dscalar(name='phi')
# theta = T.dscalar(name='theta')
# psi = T.dscalar(name='psi')

R = theano.shared(value=np.zeros([3, 3]), name='R')

R00 = T.set_subtensor(R[0, 0],  T.cos(theta)*T.cos(phi))
R10 = T.set_subtensor(R[1, 0],  T.cos(theta)*T.sin(phi))

R20 = T.set_subtensor(R[2, 0],  -T.sin(theta))

R01 = T.set_subtensor(R[0, 1],  T.sin(psi)*T.sin(theta)*T.cos(phi) - T.cos(psi)*T.sin(phi))
R11 = T.set_subtensor(R[1, 1],  T.sin(psi)*T.sin(theta)*T.sin(phi) + T.cos(psi)*T.cos(phi))
R21 = T.set_subtensor(R[2, 1],  T.sin(psi)*T.cos(theta))

R02 = T.set_subtensor(R[0, 2],  T.cos(psi)*T.sin(theta)*T.cos(phi) + T.sin(psi)*T.sin(phi))
R12 = T.set_subtensor(R[1, 2],  T.cos(psi)*T.sin(theta)*T.sin(phi) - T.sin(psi)*T.cos(phi))
R22 = T.set_subtensor(R[2, 2],  T.cos(psi)*T.cos(theta))

f = theano.function([phi, theta, psi], updates=[(R, R00, R10, R20, R01, R11, R21, R02, R12, R22)])

theano.printing.pydotprint(f, outfile="./test.png", var_with_name_simple=True)

But this gives me error at two different stage,

Traceback (most recent call last):
  File "/theanotest.py", line 38, in <module>
    f = theano.function([phi, theta, psi], updates=[(R, R00, R10, R20, R01, R11, R21, R02, R12, R22)])
  File "/usr/local/lib/python2.7/dist-packages/theano/compile/function.py", line 266, in function
    profile=profile)
  File "/usr/local/lib/python2.7/dist-packages/theano/compile/pfunc.py", line 489, in pfunc
    no_default_updates=no_default_updates)
  File "/usr/local/lib/python2.7/dist-packages/theano/compile/pfunc.py", line 186, in rebuild_collect_shared
    ' variable via the `givens` parameter') % v)
TypeError: Cannot use a shared variable (phi) as explicit input. Consider substituting a non-shared variable via the `givens` parameter

If I chage the Eurler angles to scalar values I get error as below

Traceback (most recent call last):
  File "/theanotest.py", line 38, in <module>
    f = theano.function([phi, theta, psi], updates=[(R, R00, R10, R20, R01, R11, R21, R02, R12, R22)])
  File "/usr/local/lib/python2.7/dist-packages/theano/compile/function.py", line 266, in function
    profile=profile)
  File "/usr/local/lib/python2.7/dist-packages/theano/compile/pfunc.py", line 489, in pfunc
    no_default_updates=no_default_updates)
  File "/usr/local/lib/python2.7/dist-packages/theano/compile/pfunc.py", line 191, in rebuild_collect_shared
    for (store_into, update_val) in iter_over_pairs(updates):
ValueError: too many values to unpack

Can anyone please help me with this problem?


Solution

  • The first error is exactly as the message indicates: you can't supply shared variables as inputs to Theano functions. Either use shared variables with no input parameters or regular tensors as input parameters.

    The second error is due to incorrect updates. Updates should be a list of pairs. Each pair should consist of the shared variable to be updated and a symbolic expression describing how the update should be computed.

    In this case the update might be computed like this (untested):

    Rnew = T.set_subtensor(R[0, 0],  T.cos(theta)*T.cos(phi))
    Rnew = T.set_subtensor(Rnew[1, 0],  T.cos(theta)*T.sin(phi))
    Rnew = T.set_subtensor(Rnew[2, 0],  -T.sin(theta))
    
    Rnew = T.set_subtensor(Rnew[0, 1],  T.sin(psi)*T.sin(theta)*T.cos(phi) - T.cos(psi)*T.sin(phi))
    Rnew = T.set_subtensor(Rnew[1, 1],  T.sin(psi)*T.sin(theta)*T.sin(phi) + T.cos(psi)*T.cos(phi))
    Rnew = T.set_subtensor(Rnew[2, 1],  T.sin(psi)*T.cos(theta))
    
    Rnew = T.set_subtensor(Rnew[0, 2],  T.cos(psi)*T.sin(theta)*T.cos(phi) + T.sin(psi)*T.sin(phi))
    Rnew = T.set_subtensor(Rnew[1, 2],  T.cos(psi)*T.sin(theta)*T.sin(phi) - T.sin(psi)*T.cos(phi))
    Rnew = T.set_subtensor(Rnew[2, 2],  T.cos(psi)*T.cos(theta))
    
    f = theano.function([phi, theta, psi], updates=[(R, Rnew)])