Загадочная ошибка при использовании автоградации HIPS с numpy.piecewise (ValueError: установка элемента массива с помощью последовательности.)

avatar
Alan Dong
8 апреля 2018 в 11:24
421
1
0

Я хочу использовать HIPS autograd (https://github.com/HIPS/autograd) в Python 2.7 (в блокноте Jupyter), чтобы найти параметр 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.piece. Когда я меняю прямую модель (чтобы ни одна из функций не зависела от x) на

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

ошибка исчезает. Есть идеи? Спасибо!

Источник

Ответы (1)

avatar
Alan Dong
8 апреля 2018 в 11:55
0

Кажется, numpy.piecewise не поддерживается автоградом. В итоге я изменил его на реализацию, использующую numpy.select, которая вычисляет каждую функцию во всем временном окне, а не только в той области, где активно ее условие. Это кажется неэффективным, но я полагаю, что альтернативой является написание пользовательского примитива autograd...