'This function implements both the forward and backwards pass of this
layer. The reason we do this in a single function is because for the
factorized softmax layer is hard to rely on grad and get an
optimized graph. For uniformity I\'ve implemented this method for
this layer as well (though one doesn\'t need to use it)
:param state_below: theano variable representing the input to the
softmax layer
:param target: theano variable representing the target for this
layer
:return: cost, dC_dstate_below, param_grads, new_properties
dC_dstate_below is a computational graph representing the
gradient of the cost wrt to state_below
param_grads is a list containing the gradients wrt to the
different parameters of the layer
new_properties is a dictionary containing additional properties
of the model; properties are theano expression that are
evaluated and reported by the model'

def get_grads(self, state_below, target, mask=None, reg=None, scale=None, sum_over_time=True, use_noise=True, additional_inputs=None):

    cost = self.get_cost(state_below, target, mask=mask, reg=reg, scale=scale, sum_over_time=sum_over_time, use_noise=use_noise, additional_inputs=additional_inputs)
    grads = TT.grad(cost, self.params)
    if self.additional_gradients:
        for (new_grads, to_replace, properties) in self.additional_gradients:
            (gparams, params) = new_grads
            prop_expr = [x[1] for x in properties]
            replace = [(x[0], TT.grad(cost, x[1])) for x in to_replace]
            rval = theano.clone((gparams + prop_expr), replace=replace)
            gparams = rval[:len(gparams)]
            prop_expr = rval[len(gparams):]
            self.properties += [(x[0], y) for (x, y) in zip(properties, prop_expr)]
            for (gp, p) in zip(gparams, params):
                grads[self.params.index(p)] += gp
    self.cost = cost
    self.grads = grads
    def Gvs_fn(*args):
        w = (((1 - self.model_output) * self.model_output) * state_below.shape[1])
        Gvs = TT.Lop(self.model_output, self.params, (TT.Rop(self.model_output, self.params, args) / w))
        return Gvs
    self.Gvs = Gvs_fn
    return (cost, grads)
