使用带有numpy.piecewise的HIPS autograd时的隐秘错误(ValueError:使用序列设置数组元素。)

时间:2018-04-08 11:24:19

标签: python numpy jupyter piecewise autograd

我想在Python 2.7(在Jupyter笔记本中)中使用HIPS autograd(https://github.com/HIPS/autograd)来查找参数 x 。我的正演模型(在给定时间点观察 t 作为参数 x 的函数)是 t 的分段函数。因此,我选择使用autograd.numpy.piecewise函数。我的损失(或客观)函数是一个直接的均方误差。我无法使用autograd.grad计算自动渐变。

下面的简单代码示例:

import autograd.numpy as anp
from autograd import grad

def forward_model(x, t): # it's a rectangular box of width x and height 1/x centered at the origin
    y = anp.piecewise(t, [t < -x/2., (t >= -x/2.) & (t < x/2.), t >= x/2.], [0., 1/x, 0.])
    return y

def loss(x, t, y):
    y_hat = forward_model(x, t)
    return anp.mean( (y_hat - y)**2 ) # mean squared error loss

x_star = 1. # ground truth parameter x
t = anp.linspace(-1., 1., 1001) # time points to evaluate function
y = forward_model(x_star, t)

x_init = 0.5
loss_init = loss(x_init, t, y)
grad_loss = grad(loss)
grad_init = grad_loss(x_init, t, y)

我得到的完整错误是:

ValueErrorTraceback (most recent call last) <ipython-input-507-e643ed94813b> in <module>()
     16 loss_init = loss(x_init, t, y)
     17 grad_loss = grad(loss)
---> 18 grad_init = grad_loss(x_init, t, y)

C:\Users\alan_dong\AppData\Local\Continuum\Anaconda2\lib\site-packages\autograd\wrap_util.pyc in nary_f(*args, **kwargs)
     18             else:
     19                 x = tuple(args[i] for i in argnum)
---> 20             return unary_operator(unary_f, x, *nary_op_args, **nary_op_kwargs)
     21         return nary_f
     22     return nary_operator

C:\Users\alan_dong\AppData\Local\Continuum\Anaconda2\lib\site-packages\autograd\differential_operators.pyc in grad(fun, x)
     22     arguments as `fun`, but returns the gradient instead. The function `fun`
     23     should be scalar-valued. The gradient has the same type as the argument."""
---> 24     vjp, ans = _make_vjp(fun, x)
     25     if not vspace(ans).size == 1:
     26         raise TypeError("Grad only applies to real scalar-output functions. "

C:\Users\alan_dong\AppData\Local\Continuum\Anaconda2\lib\site-packages\autograd\core.pyc in make_vjp(fun, x)
      8 def make_vjp(fun, x):
      9     start_node = VJPNode.new_root(x)
---> 10     end_value, end_node =  trace(start_node, fun, x)
     11     if end_node is None:
     12         def vjp(g): return vspace(x).zeros()

C:\Users\alan_dong\AppData\Local\Continuum\Anaconda2\lib\site-packages\autograd\tracer.pyc in trace(start_node, fun, x)
      8     with trace_stack.new_trace() as t:
      9         start_box = new_box(x, t, start_node)
---> 10         end_box = fun(start_box)
     11         if isbox(end_box) and end_box._trace == start_box._trace:
     12             return end_box._value, end_box._node

C:\Users\alan_dong\AppData\Local\Continuum\Anaconda2\lib\site-packages\autograd\wrap_util.pyc in unary_f(x)
     13                 else:
     14                     subargs = subvals(args, zip(argnum, x))
---> 15                 return fun(*subargs, **kwargs)
     16             if isinstance(argnum, int):
     17                 x = args[argnum]

<ipython-input-507-e643ed94813b> in loss(x, t, y)
      6 
      7 def loss(x, t, y):
----> 8     y_hat = forward_model(x, t)
      9     return anp.mean( (y_hat - y)**2 ) # mean squared error loss
     10 

<ipython-input-507-e643ed94813b> in forward_model(x, t)
      2 
      3 def forward_model(x, t): # it's a rectangular box of width x and height 1/x centered at the origin
----> 4     y = anp.piecewise(t, [t < -x/2., (t >= -x/2.) & (t < x/2.), t >= x/2.], [0., 1/x, 0.])
      5     return y
      6 

C:\Users\alan_dong\AppData\Local\Continuum\Anaconda2\lib\site-packages\autograd\tracer.pyc in f_wrapped(*args, **kwargs)
     46             return new_box(ans, trace, node)
     47         else:
---> 48             return f_raw(*args, **kwargs)
     49     f_wrapped.fun = f_raw
     50     f_wrapped._is_autograd_primitive = True

C:\Users\alan_dong\AppData\Local\Continuum\Anaconda2\lib\site-packages\numpy\lib\function_base.pyc in piecewise(x, condlist, funclist, *args, **kw)    1347         item
= funclist[k]    1348         if not isinstance(item, collections.Callable):
-> 1349             y[condlist[k]] = item    1350         else:    1351             vals = x[condlist[k]]

ValueError: setting an array element with a sequence.

我认为这与numpy.piecewise的funclist论证有关。当我改变正向模型(因此没有任何函数依赖于x)

y = anp.piecewise(t, [t < -x/2., (t >= -x/2.) & (t < x/2.), t >= x/2.], [0., 1., 0.])

错误消失了。有任何想法吗?谢谢!

1 个答案:

答案 0 :(得分:0)

似乎numpy.piecewise不受autograd支持。我最终将其更改为使用numpy.select的实现,该实现计算整个时间窗口中的每个函数,而不仅仅是其条件处于活动状态的区域。它似乎效率低下,但我想替代方法是编写一个自定义的autograd原语...