1
votes

I am trying to compute gradients on the following graph (this is a class method):

def __define_likelihood_computation(self):

    self.__lik_graph = tf.Graph()
    lik_graph = self.__lik_graph

    r = self.__C(self.__th).shape[1]
    m = self.__H(self.__th).shape[0]
    n = self.__F(self.__th).shape[1]
    p = self.__G(self.__th).shape[1]

    x0_mean = self.__x0_mean
    x0_cov = self.__x0_cov

    with lik_graph.as_default():
        # FIXME: Don't Repeat Yourself (in simulation and here)
        th = tf.placeholder(tf.float64, shape=[None], name='th')
        u = tf.placeholder(tf.float64, shape=[r, None], name='u')
        t = tf.placeholder(tf.float64, shape=[None], name='t')
        y = tf.placeholder(tf.float64, shape=[m, None], name='y')

        N = tf.stack([tf.shape(t)[0]])
        N = tf.reshape(N, ())

        F = tf.py_func(self.__F, [th], tf.float64, name='F')
        F.set_shape([n, n])

        C = tf.py_func(self.__C, [th], tf.float64, name='C')
        C.set_shape([n, r])

        G = tf.py_func(self.__G, [th], tf.float64, name='G')
        G.set_shape([n, p])

        H = tf.py_func(self.__H, [th], tf.float64, name='H')
        H.set_shape([m, n])

        x0_mean = tf.py_func(x0_mean, [th], tf.float64, name='x0_mean')
        x0_mean.set_shape([n, 1])

        P_0 = tf.py_func(x0_cov, [th], tf.float64, name='x0_cov')
        P_0.set_shape([n, n])

        Q = tf.py_func(self.__w_cov, [th], tf.float64, name='w_cov')
        Q.set_shape([p, p])

        R = tf.py_func(self.__v_cov, [th], tf.float64, name='v_cov')
        R.set_shape([m, m])

        I = tf.eye(n, n, dtype=tf.float64)

        def lik_loop_cond(k, P, S, t, u, x, y):
            return tf.less(k, N-1)

        def lik_loop_body(k, P, S, t, u, x, y):

            # TODO: this should be function of time
            u_t_k = tf.slice(u, [0, k], [r, 1])

            # k+1, cause zeroth measurement should not be taken into account
            y_k = tf.slice(y, [0, k+1], [m, 1])

            t_k = tf.slice(t, [k], [2], 't_k')

            # TODO: extract Kalman filter to a separate class
            def state_predict(x, t):
                Fx = tf.matmul(F, x, name='Fx')
                Cu = tf.matmul(C, u_t_k, name='Cu')
                dx = Fx + Cu
                return dx

            def covariance_predict(P, t):
                GQtG = tf.matmul(G @ Q, G, transpose_b=True)
                PtF = tf.matmul(P, F, transpose_b=True)
                dP = tf.matmul(F, P) + PtF + GQtG
                return dP

            x = tf.contrib.integrate.odeint(state_predict, x, t_k,
                                            name='state_predict')
            x = x[-1]

            P = tf.contrib.integrate.odeint(covariance_predict, P, t_k,
                                            name='covariance_predict')
            P = P[-1]

            E = y_k - tf.matmul(H, x)

            B = tf.matmul(H @ P, H, transpose_b=True) + R
            invB = tf.matrix_inverse(B)

            K = tf.matmul(P, H, transpose_b=True) @ invB

            S_k = tf.matmul(E, invB @ E, transpose_a=True)
            S_k = 0.5 * (S_k + tf.log(tf.matrix_determinant(B)))

            S = S + S_k

            # state update
            x = x + tf.matmul(K, E)

            # covariance update
            P = (I - K @ H) @ P

            k = k + 1

            return k, P, S, t, u, x, y

        k = tf.constant(0, name='k')
        P = P_0
        S = tf.constant(0.0, dtype=tf.float64, shape=[1, 1], name='S')
        x = x0_mean

        # TODO: make a named tuple of named list
        lik_loop = tf.while_loop(lik_loop_cond, lik_loop_body,
                                 [k, P, S, t, u, x, y], name='lik_loop')

        dS = tf.gradients(lik_loop[2], th)

        self.__lik_loop_op = lik_loop
        self.__dS = dS

And the evaluation itself it the following:

def dL(self, t, u, y, th=None):
    if th is None:
        th = self.__th

    self.__validate(th)
    g = self.__lik_graph

    if t.shape[0] != u.shape[1]:
        raise Exception('''t.shape[0] != u.shape[1]''')

    # run lik graph
    with tf.Session(graph=g) as sess:
        t_ph = g.get_tensor_by_name('t:0')
        th_ph = g.get_tensor_by_name('th:0')
        u_ph = g.get_tensor_by_name('u:0')
        y_ph = g.get_tensor_by_name('y:0')
        rez = sess.run(self.__dS, {th_ph: th, t_ph: t, u_ph: u, y_ph: y})

    return rez

The likelihood computation does work, it's the following:

def lik(self, t, u, y, th=None):
    if th is None:
        th = self.__th

    self.__validate(th)
    g = self.__lik_graph

    if t.shape[0] != u.shape[1]:
        raise Exception('''t.shape[0] != u.shape[1]''')

    # run lik graph
    with tf.Session(graph=g) as sess:
        t_ph = g.get_tensor_by_name('t:0')
        th_ph = g.get_tensor_by_name('th:0')
        u_ph = g.get_tensor_by_name('u:0')
        y_ph = g.get_tensor_by_name('y:0')
        rez = sess.run(self.__lik_loop_op, {th_ph: th, t_ph: t, u_ph: u,
                                            y_ph: y})

    N = len(t)
    m = y.shape[0]
    S = rez[2]
    S = S + N*m * 0.5 + np.log(2*math.pi)

    return S

When I try to compute gradients (call dL) I get the following error with traceback:

Traceback (most recent call last):
  File "", line 1, in 
  File "/home/konstunn/study/research/prod-practice1/report/tf/model.py", line 446, in 
    dL = m.dL(t, u, y)
  File "/home/konstunn/study/research/prod-practice1/report/tf/model.py", line 415, in dL
    rez = sess.run(self.__dS, {th_ph: th, t_ph: t, u_ph: u, y_ph: y})
  File "/usr/local/lib/python3.5/dist-packages/tensorflow/python/client/session.py", line 895, in run
    run_metadata_ptr)
  File "/usr/local/lib/python3.5/dist-packages/tensorflow/python/client/session.py", line 1109, in _run
    self._graph, fetches, feed_dict_tensor, feed_handles=feed_handles)
  File "/usr/local/lib/python3.5/dist-packages/tensorflow/python/client/session.py", line 413, in __init__
    self._fetch_mapper = _FetchMapper.for_fetch(fetches)
  File "/usr/local/lib/python3.5/dist-packages/tensorflow/python/client/session.py", line 233, in for_fetch
    return _ListFetchMapper(fetch)
  File "/usr/local/lib/python3.5/dist-packages/tensorflow/python/client/session.py", line 340, in __init__
    self._mappers = [_FetchMapper.for_fetch(fetch) for fetch in fetches]
  File "/usr/local/lib/python3.5/dist-packages/tensorflow/python/client/session.py", line 340, in 
    self._mappers = [_FetchMapper.for_fetch(fetch) for fetch in fetches]
  File "/usr/local/lib/python3.5/dist-packages/tensorflow/python/client/session.py", line 230, in for_fetch
    (fetch, type(fetch)))
TypeError: Fetch argument None has invalid type 

What may be a reason?

Sorry for so long post.

1

1 Answers

0
votes

I got it. The reason is that I have tf.py_func() in my graph, which is the first action performed on th, with respect to which I try to compute the gradients. It seems that there is one more limitation of tf.py_func(), that is not documented - probably considered obvious.

Maybe I should report bug (or make a feature request) and make a temporary workaround.