From 7c65f16b6195b32b2cef38a3403cd65c50ce409d Mon Sep 17 00:00:00 2001 From: Christopher Olah Date: Wed, 31 Oct 2018 16:28:26 -0700 Subject: [PATCH] Add new neuron mech notebook --- .../misc/decomposed_feature_vis_1x1.ipynb | 653 ++++++++++++++++++ 1 file changed, 653 insertions(+) create mode 100644 notebooks/misc/decomposed_feature_vis_1x1.ipynb diff --git a/notebooks/misc/decomposed_feature_vis_1x1.ipynb b/notebooks/misc/decomposed_feature_vis_1x1.ipynb new file mode 100644 index 00000000..d8f311fb --- /dev/null +++ b/notebooks/misc/decomposed_feature_vis_1x1.ipynb @@ -0,0 +1,653 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "name": "Decomposed feature vis - simple", + "version": "0.3.2", + "provenance": [] + }, + "kernelspec": { + "name": "python2", + "display_name": "Python 2" + }, + "accelerator": "GPU" + }, + "cells": [ + { + "metadata": { + "id": "JndnmDMp66FL", + "colab_type": "text" + }, + "cell_type": "markdown", + "source": [ + "##### Copyright 2018 Lucid Authors\n", + "\n", + "Licensed under the Apache License, Version 2.0 (the \"License\");" + ] + }, + { + "metadata": { + "id": "hMqWDc_m6rUC", + "colab_type": "code", + "cellView": "both", + "colab": {} + }, + "cell_type": "code", + "source": [ + "# Licensed under the Apache License, Version 2.0 (the \"License\");\n", + "# you may not use this file except in compliance with the License.\n", + "# You may obtain a copy of the License at\n", + "#\n", + "# https://www.apache.org/licenses/LICENSE-2.0\n", + "#\n", + "# Unless required by applicable law or agreed to in writing, software\n", + "# distributed under the License is distributed on an \"AS IS\" BASIS,\n", + "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n", + "# See the License for the specific language governing permissions and\n", + "# limitations under the License." + ], + "execution_count": 0, + "outputs": [] + }, + { + "metadata": { + "id": "_vAVmphMywZR", + "colab_type": "text" + }, + "cell_type": "markdown", + "source": [ + "# Decomposed Feature Visualization (rough)\n", + "\n", + "Decomposed feature visualization is a techhnique for understanding the *mechanics* of how neural network features operate. This is a very early experiment with them.\n", + "\n", + "\n" + ] + }, + { + "metadata": { + "id": "FsFc1mE51tCd", + "colab_type": "text" + }, + "cell_type": "markdown", + "source": [ + "# Setup" + ] + }, + { + "metadata": { + "id": "tavMPe3KQ8Cs", + "colab_type": "code", + "colab": {} + }, + "cell_type": "code", + "source": [ + "# Install Lucid\n", + "\n", + "#!pip install --quiet lucid==0.0.5\n", + "!pip install -U --no-deps git+https://github.com/tensorflow/lucid.git\n", + "!npm install -g svelte-cli@2.2.0" + ], + "execution_count": 0, + "outputs": [] + }, + { + "metadata": { + "id": "RBr8QbboRAdU", + "colab_type": "code", + "colab": {} + }, + "cell_type": "code", + "source": [ + "# Imports\n", + "\n", + "import numpy as np\n", + "import scipy.ndimage as nd\n", + "import tensorflow as tf\n", + "\n", + "import lucid.modelzoo.vision_models as models\n", + "from lucid.misc.io import show, load\n", + "import lucid.optvis.objectives as objectives\n", + "import lucid.optvis.param as param\n", + "import lucid.optvis.render as render\n", + "import lucid.optvis.transform as transform\n", + "\n", + "from lucid.misc.gradient_override import gradient_override_map\n", + "from lucid.misc.io.showing import _image_url\n", + "import lucid.scratch.web.svelte as lucid_svelte\n", + "from lucid.misc.channel_reducer import ChannelReducer" + ], + "execution_count": 0, + "outputs": [] + }, + { + "metadata": { + "id": "yNALaA0QRJVT", + "colab_type": "code", + "colab": {} + }, + "cell_type": "code", + "source": [ + "# Let's import a model from the Lucid modelzoo!\n", + "\n", + "model = models.InceptionV1()\n", + "model.load_graphdef()" + ], + "execution_count": 0, + "outputs": [] + }, + { + "metadata": { + "id": "8wfJn4HYffU8", + "colab_type": "code", + "colab": {} + }, + "cell_type": "code", + "source": [ + "obj = objectives.neuron(\"mixed4e_pre_relu\", 55)" + ], + "execution_count": 0, + "outputs": [] + }, + { + "metadata": { + "id": "AkPQSTOsffSn", + "colab_type": "code", + "colab": {} + }, + "cell_type": "code", + "source": [ + "with tf.Graph().as_default(), tf.Session() as sess:\n", + " t_input = tf.placeholder(\"float32\", [1, None, None, 3])\n", + " T = render.import_model(model, t_input, t_input)\n", + " loss = obj(T)\n", + " t_layer = T(\"mixed4d\")\n", + " vecs = 0.001*np.random.randn(1, 3, 3, t_layer.shape[-1])\n", + " t_layer_grad = tf.gradients(loss, t_layer)[0]\n", + " W = t_layer_grad.eval({t_layer: vecs})" + ], + "execution_count": 0, + "outputs": [] + }, + { + "metadata": { + "id": "QfWEib1yiL0Z", + "colab_type": "code", + "colab": {} + }, + "cell_type": "code", + "source": [ + "[m_layer] = [layer for layer in model.layers if layer.name == \"mixed4d\"]\n", + "prev_acts = m_layer.activations\n", + "prev_attrs = prev_acts * W[None, :]" + ], + "execution_count": 0, + "outputs": [] + }, + { + "metadata": { + "id": "TrAq2wb8v8MJ", + "colab_type": "code", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 581 + }, + "outputId": "00e50606-221d-478c-8832-d68aae28703a" + }, + "cell_type": "code", + "source": [ + "prev_attrs_ = np.concatenate([np.maximum(prev_attrs, 0), np.maximum(-prev_attrs, 0)], axis=1)[:10000]\n", + "\n", + "nmf = ChannelReducer(4, \"NMF\")\n", + "spatial_factors = nmf.fit_transform(prev_attrs_).astype(\"float32\")\n", + "channel_factors = nmf._reducer.components_.astype(\"float32\")\n", + "\n", + "param_f = lambda: param.image(120, batch=4)\n", + "obj = sum(objectives.direction_neuron(\"mixed4d\", channel_factors[i][:528] - channel_factors[i][528:], batch=i)\n", + " + 0.5*objectives.direction(\"mixed4d\", channel_factors[i][:528] - channel_factors[i][528:], batch=i)\n", + " for i in range(4))\n", + "group_icons = render.render_vis(model, obj, param_f, verbose=True, thresholds=(128, 512, 1024, 2048))[-1]" + ], + "execution_count": 31, + "outputs": [ + { + "output_type": "stream", + "text": [ + "128 230036.47\n" + ], + "name": "stdout" + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "" + ], + "text/html": [ + "" + ] + }, + "metadata": { + "tags": [] + } + }, + { + "output_type": "stream", + "text": [ + "512 277046.38\n" + ], + "name": "stdout" + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "" + ], + "text/html": [ + "" + ] + }, + "metadata": { + "tags": [] + } + }, + { + "output_type": "stream", + "text": [ + "1024 279407.88\n" + ], + "name": "stdout" + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "" + ], + "text/html": [ + "" + ] + }, + "metadata": { + "tags": [] + } + }, + { + "output_type": "stream", + "text": [ + "2048 315404.53\n" + ], + "name": "stdout" + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "" + ], + "text/html": [ + "" + ] + }, + "metadata": { + "tags": [] + } + } + ] + }, + { + "metadata": { + "colab_type": "code", + "id": "a0_9JwrmbXvd", + "colab": {} + }, + "cell_type": "code", + "source": [ + "prev_attrs__ = prev_attrs[prev_attrs.sum(1) > 100]\n", + "prev_attrs__ /= np.sqrt(1e-1 + (prev_attrs__**2).sum(1))[:, None]" + ], + "execution_count": 0, + "outputs": [] + }, + { + "metadata": { + "colab_type": "code", + "outputId": "633b6563-6376-4f78-fd0c-3cab917f4f47", + "id": "It0wT091bXvX", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 615 + } + }, + "cell_type": "code", + "source": [ + "from sklearn.cluster import KMeans\n", + "\n", + "kmeans = KMeans(8)\n", + "clusters = kmeans.fit_transform(prev_attrs__).astype(\"float32\")\n", + "channel_factors = kmeans.cluster_centers_\n", + "\n", + "print \"Clustering Done! :) \"\n", + "print \"\"\n", + "\n", + "param_f = lambda: param.image(120, batch=8)\n", + "obj = sum(objectives.direction_neuron(\"mixed4d\", channel_factors[i][:528], batch=i)\n", + " + 0.25*objectives.direction(\"mixed4d\", channel_factors[i][:528], batch=i)\n", + " for i in range(8))\n", + "group_icons = render.render_vis(model, obj, param_f, verbose=True, thresholds=(128, 512, 1024, 2048))[-1]" + ], + "execution_count": 0, + "outputs": [ + { + "output_type": "stream", + "text": [ + "Clustering Done! :) \n", + "\n", + "128 23777.04\n" + ], + "name": "stdout" + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "" + ], + "text/html": [ + "" + ] + }, + "metadata": { + "tags": [] + } + }, + { + "output_type": "stream", + "text": [ + "512 29111.822\n" + ], + "name": "stdout" + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "" + ], + "text/html": [ + "" + ] + }, + "metadata": { + "tags": [] + } + }, + { + "output_type": "stream", + "text": [ + "1024 28238.006\n" + ], + "name": "stdout" + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "" + ], + "text/html": [ + "" + ] + }, + "metadata": { + "tags": [] + } + }, + { + "output_type": "stream", + "text": [ + "WARNING:lucid.optvis.render:Interrupted optimization at step 1386.\n" + ], + "name": "stderr" + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "" + ], + "text/html": [ + "" + ] + }, + "metadata": { + "tags": [] + } + } + ] + }, + { + "metadata": { + "id": "Q1HQ6xLzH-OS", + "colab_type": "text" + }, + "cell_type": "markdown", + "source": [ + "# Neuron specific Caricatures" + ] + }, + { + "metadata": { + "id": "bXFIbKYQLL06", + "colab_type": "code", + "colab": {} + }, + "cell_type": "code", + "source": [ + "def imgToModelSize(arr):\n", + " W = model.image_shape[0]\n", + " w, h, _ = arr.shape\n", + " s = float(W) / min(w,h)\n", + " arr = nd.zoom(arr, [s, s, 1], mode=\"nearest\")\n", + " w, h, _ = arr.shape\n", + " dw, dh = (w-W)//2, (h-W)//3\n", + " return arr[dw:dw+W, dh:dh+W]" + ], + "execution_count": 0, + "outputs": [] + }, + { + "metadata": { + "id": "UVpMfwEnK5MK", + "colab_type": "code", + "colab": {} + }, + "cell_type": "code", + "source": [ + "@objectives.wrap_objective\n", + "def weighted_dot_compare(layer, batch=1, W=1):\n", + " def inner(T):\n", + " dot = tf.reduce_sum(T(layer)[batch] * T(layer)[0] * W)\n", + " return dot\n", + " return inner" + ], + "execution_count": 0, + "outputs": [] + }, + { + "metadata": { + "id": "Do3Kdtz9MLTy", + "colab_type": "code", + "colab": {} + }, + "cell_type": "code", + "source": [ + "def caricature(img, W):\n", + " layer=\"mixed4d\"\n", + " n_steps=512\n", + " cossim_pow=0.0\n", + "\n", + "\n", + " with tf.Graph().as_default(), tf.Session() as sess:\n", + " img = imgToModelSize(img)\n", + "\n", + " objective = objectives.Objective.sum([\n", + " 1.0 * weighted_dot_compare(layer, W=W),\n", + " objectives.blur_input_each_step(),\n", + " ])\n", + "\n", + " t_input = tf.placeholder(tf.float32, img.shape)\n", + " param_f = param.image(img.shape[0], decorrelate=True, fft=True, alpha=False)\n", + " param_f = tf.stack([param_f[0], t_input])\n", + "\n", + " transforms = [\n", + " transform.pad(8, mode='constant', constant_value=.5),\n", + " transform.jitter(8),\n", + " transform.random_scale([0.9, 0.95, 1.05, 1.1] + [1]*4),\n", + " transform.random_rotate(range(-5, 5) + [0]*5),\n", + " transform.jitter(2),\n", + " ]\n", + "\n", + " T = render.make_vis_T(model, objective, param_f, transforms=transforms)\n", + " loss, vis_op, t_image = T(\"loss\"), T(\"vis_op\"), T(\"input\")\n", + "\n", + " tf.global_variables_initializer().run()\n", + " for i in range(n_steps): _ = sess.run([vis_op], {t_input: img})\n", + "\n", + " result = t_image.eval(feed_dict={t_input: img})\n", + " show(result[0])" + ], + "execution_count": 0, + "outputs": [] + }, + { + "metadata": { + "id": "fe8vrMVOLXT4", + "colab_type": "code", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 701 + }, + "outputId": "1ac665d9-0db9-4c46-b91e-b71f0bca8e11" + }, + "cell_type": "code", + "source": [ + "img = load(\"https://storage.googleapis.com/lucid-static/building-blocks/examples/car2.png\")[::2,::2,:3]\n", + "\n", + "show(img)\n", + "caricature(img, W=1)\n", + "caricature(img, W=W[None, None, :])" + ], + "execution_count": 79, + "outputs": [ + { + "output_type": "display_data", + "data": { + "text/plain": [ + "" + ], + "text/html": [ + "" + ] + }, + "metadata": { + "tags": [] + } + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "" + ], + "text/html": [ + "" + ] + }, + "metadata": { + "tags": [] + } + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "" + ], + "text/html": [ + "" + ] + }, + "metadata": { + "tags": [] + } + } + ] + }, + { + "metadata": { + "id": "HBIKEhPgb2zN", + "colab_type": "code", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 701 + }, + "outputId": "0444f28c-b3bd-4cff-f0e1-af66b3c13758" + }, + "cell_type": "code", + "source": [ + "img = load(\"https://storage.googleapis.com/lucid-static/building-blocks/examples/dog_cat.png\")\n", + "\n", + "show(img)\n", + "caricature(img, W=1)\n", + "caricature(img, W=W[None, None, :])" + ], + "execution_count": 80, + "outputs": [ + { + "output_type": "display_data", + "data": { + "text/plain": [ + "" + ], + "text/html": [ + "" + ] + }, + "metadata": { + "tags": [] + } + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "" + ], + "text/html": [ + "" + ] + }, + "metadata": { + "tags": [] + } + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "" + ], + "text/html": [ + "" + ] + }, + "metadata": { + "tags": [] + } + } + ] + } + ] +} \ No newline at end of file