The error comes from the fact that since the output of your forward pass shares the same storage as the input, you should  mark the input as “dirty” with the mark_dirty() function: add self.mark_dirty(input) in your forward pass.
You can also change this to use the new style for Function:
class NegateGradient(Function):
    """ forward identity, backward negation, useful in minimax """
    @staticmethod
    def forward(ctx, input):
        ctx.mark_dirty(input)
        return input

    @staticmethod
    def backward(ctx, grad_output):
        return -grad_output

Be careful though that the new style functions (that use static methods) are used slightly differently: you should use the .apply() method instead of just calling an instance with the arguments of your forward pass.
In your particular case you should change neg_grad_b = NegateGradient()(b) to neg_grad_b = NegateGradient.apply(b).