{"action":"created","issue":{"url":"https://api.github.com/repos/fchollet/keras/issues/1777","repository_url":"https://api.github.com/repos/fchollet/keras","labels_url":"https://api.github.com/repos/fchollet/keras/issues/1777/labels{/name}","comments_url":"https://api.github.com/repos/fchollet/keras/issues/1777/comments","events_url":"https://api.github.com/repos/fchollet/keras/issues/1777/events","html_url":"https://github.com/fchollet/keras/issues/1777","id":135159163,"number":1777,"title":"Guided Backpropagation in Keras","user":{"login":"mbz","id":1122127,"avatar_url":"https://avatars.githubusercontent.com/u/1122127?v=3","gravatar_id":"","url":"https://api.github.com/users/mbz","html_url":"https://github.com/mbz","followers_url":"https://api.github.com/users/mbz/followers","following_url":"https://api.github.com/users/mbz/following{/other_user}","gists_url":"https://api.github.com/users/mbz/gists{/gist_id}","starred_url":"https://api.github.com/users/mbz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mbz/subscriptions","organizations_url":"https://api.github.com/users/mbz/orgs","repos_url":"https://api.github.com/users/mbz/repos","events_url":"https://api.github.com/users/mbz/events{/privacy}","received_events_url":"https://api.github.com/users/mbz/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":1,"created_at":"2016-02-21T04:44:19Z","updated_at":"2016-02-25T19:49:15Z","closed_at":null,"body":"I'm trying to implement Saliency Maps and Guided Backpropagation in Keras using the following code on Lasagne.\r\n\r\nhttps://github.com/Lasagne/Recipes/blob/master/examples/Saliency%20Maps%20and%20Guided%20Backpropagation.ipynb\r\n\r\nI manged to make the first part (Saliency Maps) work as follow:\r\n\r\n```\r\ndef compile_saliency_function(model):\r\n    \"\"\"\r\n    Compiles a function to compute the saliency maps and predicted classes\r\n    for a given minibatch of input images.\r\n    \"\"\"\r\n    inp = model.layers[0].get_input()\r\n    outp = model.layers[-1].get_output()\r\n    max_outp = T.max(outp, axis=1)\r\n    saliency = theano.grad(max_outp.sum(), wrt=inp)\r\n    max_class = T.argmax(outp, axis=1)\r\n    return theano.function([inp], [saliency, max_class])\r\n```\r\n\r\n```\r\ndef show_images(img_original, saliency, max_class, title):\r\n    classes = [str(x) for x in range(10)]\r\n    # get out the first map and class from the mini-batch\r\n    saliency = saliency[0]\r\n    saliency = saliency[::-1].transpose(1, 2, 0)\r\n    max_class = max_class[0]\r\n    # plot the original image and the three saliency map variants\r\n    plt.figure(figsize=(10, 10), facecolor='w')\r\n    plt.suptitle(\"Class: \" + classes[max_class] + \". Saliency: \" + title)\r\n    plt.subplot(2, 2, 1)\r\n    plt.title('input')\r\n    plt.imshow(img_original)\r\n    plt.subplot(2, 2, 2)\r\n    plt.title('abs. saliency')\r\n    plt.imshow(np.abs(saliency).max(axis=-1), cmap='gray')\r\n    plt.subplot(2, 2, 3)\r\n    plt.title('pos. saliency')\r\n    x = (np.maximum(0, saliency) / saliency.max())[:,:,0]\r\n    plt.imshow(x)\r\n    plt.subplot(2, 2, 4)\r\n    plt.title('neg. saliency')\r\n    x = (np.maximum(0, -saliency) / -saliency.min())[:,:,0]\r\n    plt.imshow(x)\r\n    # plt.show()\r\n```\r\n\r\nNow, I'm working on the second part (Guided Backpropagation) but it doesn't work. Here is the code:\r\n\r\n```\r\nclass ModifiedBackprop(object):\r\n\r\n    def __init__(self, nonlinearity):\r\n        self.nonlinearity = nonlinearity\r\n        self.ops = {}  # memoizes an OpFromGraph instance per tensor type\r\n\r\n    def __call__(self, x):\r\n        # OpFromGraph is oblique to Theano optimizations, so we need to move\r\n        # things to GPU ourselves if needed.\r\n        if theano.sandbox.cuda.cuda_enabled:\r\n            maybe_to_gpu = theano.sandbox.cuda.as_cuda_ndarray_variable\r\n        else:\r\n            maybe_to_gpu = lambda x: x\r\n        # We move the input to GPU if needed.\r\n        x = maybe_to_gpu(x)\r\n        # We note the tensor type of the input variable to the nonlinearity\r\n        # (mainly dimensionality and dtype); we need to create a fitting Op.\r\n        tensor_type = x.type\r\n        # If we did not create a suitable Op yet, this is the time to do so.\r\n        if tensor_type not in self.ops:\r\n            # For the graph, we create an input variable of the correct type:\r\n            inp = tensor_type()\r\n            # We pass it through the nonlinearity (and move to GPU if needed).\r\n            outp = maybe_to_gpu(self.nonlinearity(inp))\r\n            # Then we fix the forward expression...\r\n            op = theano.OpFromGraph([inp], [outp])\r\n            # ...and replace the gradient with our own (defined in a subclass).\r\n            op.grad = self.grad\r\n            # Finally, we memoize the new Op\r\n            self.ops[tensor_type] = op\r\n        # And apply the memoized Op to the input we got.\r\n        return self.ops[tensor_type](x)\r\n```\r\n\r\n```\r\nclass GuidedBackprop(ModifiedBackprop):\r\n    def grad(self, inputs, out_grads):\r\n        (inp,) = inputs\r\n        (grd,) = out_grads\r\n        dtype = inp.dtype\r\n        return (grd * (inp > 0).astype(dtype) * (grd > 0).astype(dtype),)\r\n```\r\n\r\n```\r\nmodded_relu = GuidedBackprop(keras.activations.relu)  # important: only instantiate this once!\r\nfor layer in model.layers:\r\n    if 'activation' in layer.get_config() and layer.get_config()['activation'] == 'relu':\r\n        layer.activation = modded_relu\r\n        # layer.activation = theano.function([],[])\r\n```\r\n\r\nI've tested the code about in Theano and it's working so my guess is that there is something wrong with the way I'm replacing the activation in the layers (last snippet).  Any idea what I'm doing wrong?"},"comment":{"url":"https://api.github.com/repos/fchollet/keras/issues/comments/188949775","html_url":"https://github.com/fchollet/keras/issues/1777#issuecomment-188949775","issue_url":"https://api.github.com/repos/fchollet/keras/issues/1777","id":188949775,"user":{"login":"francescopittaluga","id":3466166,"avatar_url":"https://avatars.githubusercontent.com/u/3466166?v=3","gravatar_id":"","url":"https://api.github.com/users/francescopittaluga","html_url":"https://github.com/francescopittaluga","followers_url":"https://api.github.com/users/francescopittaluga/followers","following_url":"https://api.github.com/users/francescopittaluga/following{/other_user}","gists_url":"https://api.github.com/users/francescopittaluga/gists{/gist_id}","starred_url":"https://api.github.com/users/francescopittaluga/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/francescopittaluga/subscriptions","organizations_url":"https://api.github.com/users/francescopittaluga/orgs","repos_url":"https://api.github.com/users/francescopittaluga/repos","events_url":"https://api.github.com/users/francescopittaluga/events{/privacy}","received_events_url":"https://api.github.com/users/francescopittaluga/received_events","type":"User","site_admin":false},"created_at":"2016-02-25T19:49:15Z","updated_at":"2016-02-25T19:49:15Z","body":"The following works. It's kind of hacky tho. \r\n\r\n```python\r\nr = 1    # Set to index of one of the layers in Keras model with relu activation \r\nrelu = model.layers[r].activation \r\nmodded_relu = GuidedBackprop(relu)\r\nrelu_layers = [layer for layer in model.layers if getattr(layer, 'activation', None) is relu]\r\nfor layer in relu_layers:\r\n    layer.activation = modded_relu\r\n```"}}