Skip to content
This repository was archived by the owner on Dec 2, 2023. It is now read-only.
This repository was archived by the owner on Dec 2, 2023. It is now read-only.

Unable to call Hessian-vector product function if function calls other functions #93

@wiso

Description

@wiso

Sorry if the example is not very minimal. I have a function defined as

sum_C -log poisson(observed_C | sum_P {eff_CP @ (n_P * mu_P)})

where everything is constant except for mu_P. eff_CP is the element of a matrix, while the others are 1D vectors. @ is matrix multiplication.

import numpy as np
from scipy import stats
from scipy.special import gammaln, digamma

def logpoisson(lam, n):
    return n * np.log(lam) - lam - gammaln(n + 1.0)

import tangent
from tangent.grads import adjoint
@adjoint(gammaln)
def dgammaln(result, x):
  d[x] = d[result] * digamma(x)

def hessian(f):
    vhp = tangent.grad(tangent.grad(f))
    last_arg = vhp.__code__.co_varnames[vhp.__code__.co_argcount - 1]  # bad solution
    def hf(x, *args):
        H = []
        for i in range(x.size):
            v = np.eye(1, x.size, i)[0]
            H.append(vhp(x, *args, **{last_arg:v}))
        return np.array(H)
    return hf

def function(pars, obs, ntrue, efficiencies):
    mus = pars[:4]  # I need this in futures
    # pars now has size 4, so mus and pars are the same thing
    # if I use directly pars, it works
    expected = np.dot(efficiencies, ntrue * mus)
    # p = logpoisson(expected, obs)  # this doesn't work
    p = obs * np.log(expected) - expected - gammaln(obs + 1.0)  # this works
    return -np.sum(p)

grad = tangent.grad(function)
hess = hessian(function)

ntrues = np.array([8109.63147251,  636.80207692,  362.09635052,  105.68754852])
efficiencies = np.array([[8.48528557e-02, 1.16218361e-02, 1.60701261e-02, 2.14594047e-04],
       [1.49223448e-01, 2.25235106e-02, 3.32789360e-02, 5.09044476e-04],
       [7.06510161e-02, 5.48355317e-02, 4.54045768e-02, 1.75636472e-03],
       [3.41855208e-02, 6.04847808e-02, 3.98815566e-02, 1.87227331e-03],
       [6.47040512e-03, 1.91409691e-02, 1.20408359e-02, 8.01323682e-04],
       [1.64533523e-03, 5.70742974e-03, 3.62071954e-03, 3.07357073e-04],
       [1.82974652e-02, 2.61130198e-02, 3.61665791e-02, 2.17032553e-02],
       [1.48041680e-02, 2.95195735e-02, 3.27501289e-02, 2.23425697e-02],
       [6.04401223e-03, 1.28281121e-02, 1.48972295e-02, 9.19357318e-03]])

obs = np.dot(efficiencies, ntrues)

# this works, return 0, 0, 0, 0 since this is the minimum
grad(np.array([1, 1, 1, 1]), obs, ntrues, efficiencies)
# we can introduce more argument, the derivative wrt them is 0
grad(np.array([1.2, 1, 1, 1, 100]), obs, ntrues, efficiencies)

hess(np.array([1, 1, 1, 1, 100.]), obs, ntrues, efficiencies)

If in the function I call another function

p = logpoisson(expected, obs)  # this doesn't work

instead of inlining when computing the hessian I get

IndexError                                Traceback (most recent call last)
<ipython-input-19-83985776cc70> in <module>
----> 1 hess(np.array([1, 1, 1, 1, 100.]), obs, ntrues, efficiencies)

<ipython-input-2-9aa78801ca8b> in hf(x, *args)
      6         for i in range(x.size):
      7             v = np.eye(1, x.size, i)[0]
----> 8             H.append(vhp(x, *args, **{last_arg:v}))
      9         return np.array(H)
     10     return hf

/tmp/tmph8lq_o2h/tangent_7e31.py in ddfunctiondparsdpars(pars, obs, ntrue, efficiencies, bminus_np_sum_p, bbpars)
     54 
     55     # Beginning of backward pass
---> 56     _4 = tangent.pop(_stack, '_c541ac94')
     57 
     58     # Grad of: bpars[_4] = _bpars

~/venv3/lib/python3.7/site-packages/tangent/utils.py in pop(stack, op_id)
    669   """
    670   if __debug__:
--> 671     pushed_value, pushed_op_id = stack.pop()
    672     assert pushed_op_id == op_id, 'Wanted %s, got %s' % (op_id, pushed_op_id)
    673   else:

~/venv3/lib/python3.7/site-packages/tangent/utils.py in pop(self)
     59 
     60   def pop(self):
---> 61     return self._stack.pop()
     62 
     63   def __len__(self):

IndexError: pop from empty list

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions