# Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # https://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. !pip install --quiet lucid==0.0.5 !npm install -g svelte-cli@2.2.0 import numpy as np import tensorflow as tf import lucid.modelzoo.vision_models as models from lucid.misc.io import show import lucid.optvis.objectives as objectives import lucid.optvis.param as param import lucid.optvis.render as render import lucid.optvis.transform as transform from lucid.misc.io import show, load from lucid.misc.io.reading import read from lucid.misc.io.showing import _image_url, _display_html import lucid.scratch.web.svelte as lucid_svelte model = models.InceptionV1() model.load_graphdef() %%html_define_svelte ChannelAttrWidget
{{#each attrsPos as attr}}
{{attr.v}}
{{/each}} {{#if attrsPos.length > 5}}

{{/if}}
...
{{#each attrsNeg as attr}}
{{attr.v}}
{{/each}}

%%html_define_svelte BarsWidget
{{#each vals as val}}
{{/each}}

layer_spritemap_sizes = { 'mixed3a' : 16, 'mixed3b' : 21, 'mixed4a' : 22, 'mixed4b' : 22, 'mixed4c' : 22, 'mixed4d' : 22, 'mixed4e' : 28, 'mixed5a' : 28, } def googlenet_spritemap(layer): assert layer in layer_spritemap_sizes size = layer_spritemap_sizes[layer] url = "https://storage.googleapis.com/lucid-static/building-blocks/googlenet_spritemaps/sprite_%s_channel_alpha.jpeg" % layer return size, url def score_f(logit, name): if name is None: return 0 elif name == "logsumexp": base = tf.reduce_max(logit) return base + tf.log(tf.reduce_sum(tf.exp(logit-base))) elif name in model.labels: return logit[model.labels.index(name)] else: raise RuntimeError("Unsupported") def channel_attr_simple(img, layer, class1, class2, n_show=4): # Set up a graph for doing attribution... with tf.Graph().as_default(), tf.Session() as sess: t_input = tf.placeholder_with_default(img, [None, None, 3]) T = render.import_model(model, t_input, t_input) # Compute activations acts = T(layer).eval() # Compute gradient logit = T("softmax2_pre_activation")[0] score = score_f(logit, class1) - score_f(logit, class2) t_grad = tf.gradients([score], [T(layer)])[0] grad = t_grad.eval() # Let's do a very simple linear approximation attribution. # That is, we say the attribution of y to x is # the rate at which x changes y times the value of x. attr = (grad*acts)[0] # Then we reduce down to channels. channel_attr = attr.sum(0).sum(0) # Now we just need to present the results. # Get spritemaps spritemap_n, spritemap_url = googlenet_spritemap(layer) # Let's show the distribution of attributions print "Distribution of attribution accross channels:" print "" lucid_svelte.BarsWidget({"vals" : [float(v) for v in np.sort(channel_attr)[::-1]]}) # Let's pick the most extreme channels to show ns_pos = list(np.argsort(-channel_attr)[:n_show]) ns_neg = list(np.argsort(channel_attr)[:n_show][::-1]) # ... and show them with ChannelAttrWidget print "" print "Top", n_show, "channels in each direction:" print "" lucid_svelte.ChannelAttrWidget({ "spritemap_url": spritemap_url, "sprite_size": 110, "sprite_n_wrap": spritemap_n, "attrsPos": [{"n": n, "v": str(float(channel_attr[n]))[:5]} for n in ns_pos], "attrsNeg": [{"n": n, "v": str(float(channel_attr[n]))[:5]} for n in ns_neg] }) img = load("https://storage.googleapis.com/lucid-static/building-blocks/examples/dog_cat.png") channel_attr_simple(img, "mixed4d", "Labrador retriever", "tiger cat", n_show=3) img = load("https://storage.googleapis.com/lucid-static/building-blocks/examples/flowers.png") channel_attr_simple(img, "mixed4d", "vase", "lemon", n_show=3) img = load("https://storage.googleapis.com/lucid-static/building-blocks/examples/sunglasses_tux.png") channel_attr_simple(img, "mixed4d", "bow tie", "sunglasses", n_show=3) img = load("https://storage.googleapis.com/lucid-static/building-blocks/examples/dog_cat.png") channel_attr_simple(img, "mixed4d", "Labrador retriever", "tiger cat", n_show=30) def channel_attr_path(img, layer, class1, class2, n_show=4, stochastic_path=False, N = 100): # Set up a graph for doing attribution... with tf.Graph().as_default(), tf.Session() as sess: t_input = tf.placeholder_with_default(img, [None, None, 3]) T = render.import_model(model, t_input, t_input) # Compute activations acts = T(layer).eval() # Compute gradient logit = T("softmax2_pre_activation")[0] score = score_f(logit, class1) - score_f(logit, class2) t_grad = tf.gradients([score], [T(layer)])[0] # Inegrate on a path from acts=0 to acts=acts attr = np.zeros(acts.shape[1:]) for n in range(N): acts_ = acts * float(n) / N if stochastic_path: acts_ *= (np.random.uniform(0, 1, [528])+np.random.uniform(0, 1, [528]))/1.5 grad = t_grad.eval({T(layer): acts_}) attr += 1.0 / N * (grad*acts)[0] # Then we reduce down to channels. channel_attr = attr.sum(0).sum(0) # Now we just need to present the results. # Get spritemaps spritemap_n, spritemap_url = googlenet_spritemap(layer) # Let's show the distribution of attributions print "Distribution of attribution accross channels:" print "" lucid_svelte.BarsWidget({"vals" : [float(v) for v in np.sort(channel_attr)[::-1]]}) # Let's pick the most extreme channels to show ns_pos = list(np.argsort(-channel_attr)[:n_show]) ns_neg = list(np.argsort(channel_attr)[:n_show][::-1]) # ... and show them with ChannelAttrWidget print "" print "Top", n_show, "channels in each direction:" print "" lucid_svelte.ChannelAttrWidget({ "spritemap_url": spritemap_url, "sprite_size": 110, "sprite_n_wrap": spritemap_n, "attrsPos": [{"n": n, "v": str(float(channel_attr[n]))[:5]} for n in ns_pos], "attrsNeg": [{"n": n, "v": str(float(channel_attr[n]))[:5]} for n in ns_neg] }) def compare_attr_methods(img, class1, class2): _display_html("

Linear Attribution

") channel_attr_simple(img, "mixed4d", class1, class2, n_show=10) _display_html("

Path Integrated Attribution

") channel_attr_path(img, "mixed4d", class1, class2, n_show=10) _display_html("

Stochastic Path Integrated Attribution

") channel_attr_path(img, "mixed4d", class1, class2, n_show=10, stochastic_path=True) img = load("https://storage.googleapis.com/lucid-static/building-blocks/examples/dog_cat.png") compare_attr_methods(img, "Labrador retriever", "tiger cat") img = load("https://storage.googleapis.com/lucid-static/building-blocks/examples/flowers.png") compare_attr_methods(img, "vase", "lemon") img = load("https://storage.googleapis.com/lucid-static/building-blocks/examples/pig.jpeg") compare_attr_methods(img, "hog", "dalmatian")