'Computes the expression of the gradients of the cost with respect to
all parameters of the model.
:type state_below: tensor or layer
:param state_below: The theano expression (or groundhog layer)
representing the input of the cost layer
:type target: tensor or layer
:param target: The theano expression (or groundhog layer)
representing the target (used to evaluate the prediction of the
output layer)
:type mask: None or mask or layer
:param mask: Mask, depicting which of the predictions should be
ignored (e.g. due to them resulting from padding a sequence
with 0s)
:type temp: float or tensor scalar
:param temp: scalar representing the temperature that should be used
when sampling from the output distribution
:type reg: None or layer or theano scalar expression
:param reg: additional regularization term that should be added to
the cost
:type scale: float or None or theano scalar
:param scale: scaling factor with which the cost is multiplied
:type additional_gradients: list of tuples of the form
(param, gradient)
:param additional_gradiens: A list of tuples. Each tuple has as its
first element the parameter, and as second element a gradient
expression that should be added to the gradient resulting from the
cost. Not all parameters need to have an additional gradient.
:type sum_over_time: bool or None
:param sum_over_time: this flag overwrites the value given to this
property in the constructor of the class
:type use_noise: bool
:param use_noise: flag. If true, noise is used when computing the
output of the model
:type no_noise_bias: bool
:param no_noise_bias: flag, stating if weight noise should be added
to the bias as well, or only to the weights'

def get_grads(self, state_below, target=None, mask=None, temp=1, reg=None, scale=None, additional_gradients=None, sum_over_time=None, use_noise=True, additional_inputs=None, no_noise_bias=False):

    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, no_noise_bias=no_noise_bias)
    grads = TT.grad(cost.mean(), self.params)
    if additional_gradients:
        for (p, gp) in additional_gradients:
            if (p in self.params):
                grads[self.params.index(p)] += gp
    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
    return (cost, grads)
