def zeros(self): return {k : zeros_like(v) for k, v in getval(self).iteritems()}
def zeros(self): return [zeros_like(v) for v in getval(self)]
def __lt__(self, other): return getval(self) < getval(other) def __gt__(self, other): return getval(self) > getval(other)
def __gt__(self, other): return getval(self) > getval(other) class FloatNode(NumericNode):
def zeros(self): return {k: zeros_like(v) for k, v in getval(self).iteritems()}
def __gt__(self, other): return getval(self) > getval(other)
def __lt__(self, other): return getval(self) < getval(other)
def gradfun(g): idxs = np.argmax(getval(x)) return untake(g, np.unravel_index(idxs, x.shape))
def grad_np_concatenate(g): idxs = np.cumsum([a.shape[axis] for a in getval(arr_list)[:-1]]) return np.split(g, idxs, axis=axis)
import itertools as it from functools import partial from core import primitive, getval, untake P = primitive # ----- Operator gradients ----- I = lambda x : x # Identity operator op.neg = P(op.neg, lambda ans, x : [op.neg]) op.add = P(op.add, lambda ans, x, y : unbroadcast(ans, x, y, [I, I])) op.mul = P(op.mul, lambda ans, x, y : unbroadcast(ans, x, y, [lambda g : y * g, lambda g : x * g])) op.sub = P(op.sub, lambda ans, x, y : unbroadcast(ans, x, y, [I, op.neg])) op.div = P(op.div, lambda ans, x, y : unbroadcast(ans, x, y, [lambda g : g / y, lambda g : - g * x / y**2])) op.pow = P(op.pow, lambda ans, x, y : unbroadcast(ans, x, y, [lambda g : g * y * x ** (y - 1), lambda g : g * np.log(x) * x ** y])) isarray = lambda x : isinstance(getval(x), np.ndarray) isfloat = lambda x : isinstance(getval(x), float) def unbroadcast(ans, x, y, funs): return [unbroadcast_fun(ans, x, funs[0]), unbroadcast_fun(ans, y, funs[1])] def unbroadcast_fun(ans, x, fun): if isfloat(x) and isarray(ans): return lambda g : np.sum(fun(g)) elif isarray(x): shape = x.shape def new_fun(g): result = fun(g) while result.ndim > len(shape): result = np.sum(result, axis=0)