{"id":2088,"date":"2020-09-28T17:20:54","date_gmt":"2020-09-28T17:20:54","guid":{"rendered":"https:\/\/data-science.gotoauthority.com\/2020\/09\/28\/looking-inside-the-blackbox-how-to-trick-a-neural-network\/"},"modified":"2020-09-28T17:20:54","modified_gmt":"2020-09-28T17:20:54","slug":"looking-inside-the-blackbox-how-to-trick-a-neural-network","status":"publish","type":"post","link":"https:\/\/wealthrevelation.com\/data-science\/2020\/09\/28\/looking-inside-the-blackbox-how-to-trick-a-neural-network\/","title":{"rendered":"Looking Inside The Blackbox: How To Trick A Neural Network"},"content":{"rendered":"<div id=\"post-\">\n<p><b>By <a href=\"https:\/\/www.linkedin.com\/in\/wfalcon\/\" target=\"_blank\" rel=\"noopener noreferrer\">William Falcon<\/a>, Founder PyTorch Lightning<\/b><\/p>\n<p><img alt=\"Image for post\" class=\"aligncenter\" src=\"https:\/\/miro.medium.com\/max\/540\/1*sM9x0M1YOD0COSWlade5VQ.gif\" width=\"100%\"><\/p>\n<p>Using gradient ascent to figure out how to change an input to be classified as a 5. (All images are the author\u2019s own with all rights reserved).<\/p>\n<p>Neural networks get a bad reputation for being black boxes. And while it certainly takes creativity to understand their decision making, they are really not as opaque as people would have you believe.<\/p>\n<p>In this tutorial, I\u2019ll show you how to use backpropagation to change the input as to classify it as whatever you would like.<\/p>\n<p>Follow along using this\u00a0<a href=\"https:\/\/colab.research.google.com\/drive\/16HVAJHdCkyj7W43Q3ZChnxZ7DOwx6K5i?usp=sharing\" rel=\"noopener noreferrer\" target=\"_blank\">colab<\/a>.<\/p>\n<p>(This work was co-written with\u00a0<a href=\"https:\/\/twitter.com\/alfcnz\" rel=\"noopener noreferrer\" target=\"_blank\">Alfredo Canziani<\/a>\u00a0ahead of an upcoming video)<\/p>\n<p>\u00a0<\/p>\n<h3>Humans as black boxes<\/h3>\n<p>\u00a0<br \/>Let\u2019s consider the case of humans. If I show you the following input:<\/p>\n<p><img alt=\"Image for post\" class=\"aligncenter\" src=\"https:\/\/miro.medium.com\/max\/162\/1*D8LBqpJ_sUeTTFigh9Ymbw.png\"><\/p>\n<p>there\u2019s a good chance you have no idea whether this is a 5 or a 6. In fact, I believe that I could even make a case for convincing you that this\u00a0<em>might<\/em>\u00a0also be an 8.<\/p>\n<p>Now, if you asked a human what they would have to do to make something more into a 5 you might visually do something like this:<\/p>\n<p><img alt=\"Image for post\" class=\"aligncenter\" src=\"https:\/\/miro.medium.com\/max\/140\/1*sWJfKtj79udYyVR5IHlVug.png\"><\/p>\n<p>And if I wanted you to make this more into an 8, you might do something like this:<\/p>\n<p><img alt=\"Image for post\" class=\"aligncenter\" src=\"https:\/\/miro.medium.com\/max\/143\/1*3YohOhuCn8srJGP9IUoOfQ.png\"><\/p>\n<p>Now, the answer to this question is not easy to explain in a few if statements or by looking at a few coefficients (yes, I\u2019m looking at you regression). Unfortunately, with certain types of inputs (images, sound, video, etc\u2026) explainability certainly becomes much harder\u00a0<strong>but not impossible<\/strong>.<\/p>\n<p>\u00a0<\/p>\n<h3>Asking the neural network<\/h3>\n<p>\u00a0<br \/>How would a neural network answer the same questions I posed above? Well, to answer that, we can use gradient ascent to do exactly that.<\/p>\n<p>Here\u2019s how the neural network thinks we would need to modify the input to make it more into a 5.<\/p>\n<p><img alt=\"Image for post\" class=\"aligncenter\" src=\"https:\/\/miro.medium.com\/max\/177\/1*F_Ygs_zdc4qSiYjsoZs7lg.png\"><\/p>\n<p>There are two interesting results from this. First, the black areas are where the network things we need to remove pixel density from. Second, the yellow areas are where it thinks we need to add more pixel density.<\/p>\n<p>We can take a step in that gradient direction by adding the gradients to the original image. We could of course repeat this procedure over and over again to eventually morph the input into the prediction we are hoping for.<\/p>\n<p><img alt=\"Image for post\" class=\"aligncenter\" src=\"https:\/\/miro.medium.com\/max\/864\/1*T13Yuv_h1AjZR7A_toCq_A.png\" width=\"100%\"><\/p>\n<p>You can see that the black patch at the bottom left of the image is\u00a0<strong>very similar\u00a0<\/strong>to what a human might think to do as well.<\/p>\n<div>\n<img src=\"https:\/\/miro.medium.com\/max\/446\/1*ki5vQr25V0Nhkg0_XjHn7A.png\" alt=\"Figure\"><br \/><span><\/p>\n<p>Human adds black on the left corner. Network suggests the same<\/p>\n<p><\/span>\n<\/div>\n<p>\u00a0<\/p>\n<p>What about making the input look more like an 8? Here\u2019s how the network thinks you would have to change the input.<\/p>\n<p><img alt=\"Image for post\" class=\"aligncenter\" src=\"https:\/\/miro.medium.com\/max\/146\/1*Oet1NvRUkfscIabJ2h9kTA.png\"><\/p>\n<p>The notable things, here again, are that there is a black mass at the bottom left and a bright mass around the middle. If we add this with the input we get the following result:<\/p>\n<p><img alt=\"Image for post\" class=\"aligncenter\" src=\"https:\/\/miro.medium.com\/max\/405\/1*ghK7Hg-IZ7rPCLkLx6QMbA.png\" width=\"100%\"><\/p>\n<p>In this case, I\u2019m not particularly convinced that we\u2019ve turned this 5 into an 8. However, we\u2019ve made less of a 5, and the argument to convince you this is an 8 would certainly be easier to win using the image on the right instead of the image on the left.<\/p>\n<p>\u00a0<\/p>\n<h3>Gradients are your guides<\/h3>\n<p>\u00a0<br \/>In regression analysis, we look at coefficients to tell us about what we\u2019ve learned. In a random forest, we can look at decision nodes.<\/p>\n<p>In neural networks, it comes down to how\u00a0<strong>creative<\/strong>\u00a0we are at using gradients. To classify this digit, we generated a distribution over possible predictions.<\/p>\n<p>This is what we call the\u00a0<em>forward pass.<\/em><\/p>\n<div>\n<img src=\"https:\/\/miro.medium.com\/max\/540\/1*tBsGoiroGf3iOvPl595MOw.gif\" alt=\"Figure\" width=\"100%\"><br \/><span><\/p>\n<p>During the forward pass we calculate a probability distribution over outputs<\/p>\n<p><\/span>\n<\/div>\n<p>\u00a0<\/p>\n<p>In code it looks like this (<a href=\"https:\/\/colab.research.google.com\/drive\/16HVAJHdCkyj7W43Q3ZChnxZ7DOwx6K5i?usp=sharing\" rel=\"noopener noreferrer\" target=\"_blank\">follow along using this colab<\/a>):<\/p>\n<p><img alt=\"Image for post\" class=\"aligncenter\" src=\"https:\/\/miro.medium.com\/max\/1124\/1*2G1Fz_zlq3fbeOTNOShfNQ.png\" width=\"100%\"><\/p>\n<p>Now imagine that we wanted to trick the network into predicting \u201c5\u201d for the input x. Then the way to do this is to give it an image (x), calculate the predictions for the image and then\u00a0<strong>maximize<\/strong>\u00a0the probablitity of predicting the label \u201c5\u201d.<\/p>\n<p>To do this we can use gradient ascent to calculate the gradients of a prediction at the 6th index (ie: label = 5) (<strong>p<\/strong>) with respect to the input\u00a0<strong>x<\/strong>.<\/p>\n<p><img alt=\"Image for post\" class=\"aligncenter\" src=\"https:\/\/miro.medium.com\/max\/71\/1*uZ7HiO7nggFm1lrxKE9nbA.png\"><\/p>\n<p>To do this in code we feed the input x as a parameter to the neural network, pick the 6th prediction (because we have labels: 0, 1, 2, 3, 4 , 5, \u2026) and the 6th index means label \u201c5\u201d.<\/p>\n<p>Visually this looks like:<\/p>\n<div>\n<img src=\"https:\/\/miro.medium.com\/max\/540\/1*sM9x0M1YOD0COSWlade5VQ.gif\" alt=\"Figure\" width=\"100%\"><br \/><span><\/p>\n<p>Gradient of the prediction of a \u201c5\u201d with respect to the input.<\/p>\n<p><\/span>\n<\/div>\n<p>\u00a0<\/p>\n<p>And in code:<\/p>\n<p><img alt=\"Image for post\" class=\"aligncenter\" src=\"https:\/\/miro.medium.com\/max\/1013\/1*Qboy70qx45AVW8X1ReWWQw.png\" width=\"100%\"><\/p>\n<p>When we call .backward() the process that happens can be visualized by the previous animation.<\/p>\n<p>Now that we calculated the gradients, we can visualize and plot them:<\/p>\n<p><img alt=\"Image for post\" class=\"aligncenter\" src=\"https:\/\/miro.medium.com\/max\/791\/1*4HNRLYwF7EhL5lUy44134w.png\"><\/p>\n<p><img alt=\"Image for post\" class=\"aligncenter\" src=\"https:\/\/miro.medium.com\/max\/179\/1*I8LeZ8q9Ub5kHYZu35Wxbg.png\"><\/p>\n<p>The above gradient looks like random noise because the network has not yet been trained\u2026 However, once we do train the network, the gradients will be more informative:<\/p>\n<p><img alt=\"Image for post\" class=\"aligncenter\" src=\"https:\/\/miro.medium.com\/max\/167\/1*jw30tM6JfPV24pphbK86Yw.png\"><\/p>\n<p>\u00a0<\/p>\n<h3>Automating this via Callbacks<\/h3>\n<p>\u00a0<br \/>This is a hugely helpful tool in helping illuminate what happens inside your network as it trains. In this case, we would want to automate this process so that it happens automatically in training.<\/p>\n<p>For this, we\u2019ll use PyTorch Lightning to implement our neural network:<\/p>\n<p>The complicated code to automatically plot what we described here, can be abstracted out into a Callback in Lightning. A callback is a small program that is called at the parts of training you might care about.<\/p>\n<p>In this case, when a training batch is processed, we want to generate these images in case some of the inputs are confused.<\/p>\n<p>But&#8230; we\u2019ve made it even easier with pytorch-lightning-bolts which you can simply install<\/p>\n<div>\n<pre><code>pip install pytorch-lightning-bolts<\/code><\/pre>\n<\/div>\n<p>and import the callback into your training code<\/p>\n<p>\u00a0<\/p>\n<h3>Putting it all together<\/h3>\n<p>\u00a0<br \/>Finally we can train our model and automatically generate images when logits are \u201cconfused\u201d<\/p>\n<p>and tensorboard will automatically generate images that look like this:<\/p>\n<p><img alt=\"Image for post\" class=\"aligncenter\" src=\"https:\/\/miro.medium.com\/max\/452\/1*waxeunPcryqJfY7-ZmQ4gQ.png\" width=\"100%\"><\/p>\n<p><img alt=\"Image for post\" class=\"aligncenter\" src=\"https:\/\/miro.medium.com\/max\/482\/1*xHkFSrs1ZO9cg7W8ARBiiQ.png\" width=\"100%\"><\/p>\n<p>\u00a0<\/p>\n<h3>Summary<\/h3>\n<p>\u00a0<br \/><img alt=\"Image for post\" class=\"aligncenter\" src=\"https:\/\/miro.medium.com\/max\/959\/1*m_SjvsfRsAIRrXtSHNryDg.png\" width=\"100%\"><\/p>\n<p>In summary: You learned how to look inside the blackbox using PyTorch, learned the intuition, wrote a callback in PyTorch Lightning and automatically got your Tensorboard instance to plot questionable predictions<\/p>\n<p>Try it yourself with\u00a0<a href=\"https:\/\/github.com\/PyTorchLightning\/pytorch-lightning\" rel=\"noopener noreferrer\" target=\"_blank\">PyTorch Lightning<\/a>\u00a0and\u00a0<a href=\"https:\/\/github.com\/PyTorchLightning\/pytorch-lightning-bolts\" rel=\"noopener noreferrer\" target=\"_blank\">PyTorch Lightning Bolts<\/a>.<\/p>\n<p>(This article was written ahead of an upcoming video where me (William) and\u00a0<a href=\"https:\/\/twitter.com\/alfcnz\" rel=\"noopener noreferrer\" target=\"_blank\">Alfredo Canzian<\/a>i show you how to code this from scratch).<\/p>\n<p>\u00a0<br \/><b>Bio: <a href=\"https:\/\/www.linkedin.com\/in\/wfalcon\/\" target=\"_blank\" rel=\"noopener noreferrer\">William Falcon<\/a><\/b> is an AI Researcher, and Founder at PyTorch Lightning. He is trying to understand the brain, build AI and use it at scale.<\/p>\n<p><a href=\"https:\/\/towardsdatascience.com\/peering-inside-the-blackbox-how-to-trick-a-neural-network-757c90a88a73\" target=\"_blank\" rel=\"noopener noreferrer\">Original<\/a>. Reposted with permission.<\/p>\n<p><b>Related:<\/b><\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>https:\/\/www.kdnuggets.com\/2020\/09\/inside-blackbox-trick-neural-network.html<\/p>\n","protected":false},"author":0,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[2],"tags":[],"_links":{"self":[{"href":"https:\/\/wealthrevelation.com\/data-science\/wp-json\/wp\/v2\/posts\/2088"}],"collection":[{"href":"https:\/\/wealthrevelation.com\/data-science\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wealthrevelation.com\/data-science\/wp-json\/wp\/v2\/types\/post"}],"replies":[{"embeddable":true,"href":"https:\/\/wealthrevelation.com\/data-science\/wp-json\/wp\/v2\/comments?post=2088"}],"version-history":[{"count":0,"href":"https:\/\/wealthrevelation.com\/data-science\/wp-json\/wp\/v2\/posts\/2088\/revisions"}],"wp:attachment":[{"href":"https:\/\/wealthrevelation.com\/data-science\/wp-json\/wp\/v2\/media?parent=2088"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wealthrevelation.com\/data-science\/wp-json\/wp\/v2\/categories?post=2088"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wealthrevelation.com\/data-science\/wp-json\/wp\/v2\/tags?post=2088"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}