Example #1
0
def neuron_groups(img, filename, layer, n_groups=10, attr_classes=None, filenumber=0):
    # Compute activations
    dirname = '../images/' + filename+'/'
    if attr_classes is None:
        attr_classes = []
    with tf.Graph().as_default(), tf.Session():
        t_input = tf.placeholder_with_default(img, [None, None, 3])
        T = render.import_model(model, t_input, t_input)
        acts = T(layer).eval()

    # We'll use ChannelReducer (a wrapper around scikit learn's factorization tools)
    # to apply Non-Negative Matrix factorization (NMF).

    nmf = ChannelReducer(n_groups, "NMF")
    spatial_factors = nmf.fit_transform(acts)[0].transpose(2, 0, 1).astype("float32")
    channel_factors = nmf._reducer.components_.astype("float32")

    # Let's organize the channels based on their horizontal position in the image

    x_peak = np.argmax(spatial_factors.max(1), 1)
    ns_sorted = np.argsort(x_peak)
    spatial_factors = spatial_factors[ns_sorted]
    channel_factors = channel_factors[ns_sorted]

    # And create a feature visualziation of each group

    param_f = lambda: param.image(80, batch=n_groups)
    obj = sum(objectives.direction(layer, channel_factors[i], batch=i)
              for i in range(n_groups))
    group_icons = render.render_vis(model, obj, param_f, verbose=False)[-1]

    # We'd also like to know about attribution

    # First, let's turn each group into a vector over activations
    group_vecs = [spatial_factors[i, ..., None] * channel_factors[i]
                  for i in range(n_groups)]

    attrs = np.asarray([raw_class_group_attr(img, layer, attr_class, group_vecs)
                        for attr_class in attr_classes])

    print(
        attrs
    )
    try:
        os.mkdir(dirname )

    except Exception as e:
        print(e)
    # Let's render the visualization!
    finally:
        with open(dirname + '/attrs.txt', 'w') as f_w:
            f_w.write(str(attrs))
        for index, icon in enumerate(group_icons):
            imgdata=to_image_url(icon)
            print(imgdata)
            imgdata = base64.b64decode(str(imgdata))
            print(imgdata)
            with open(dirname + str(index) + '.png', 'wb') as f_jpg:
                f_jpg.write(imgdata)
Example #2
0
def neuron_groups(model, img, layer, n_groups=6, attr_classes=[]):
    # Compute activations

    with tf.Graph().as_default(), tf.Session():
        t_input = tf.placeholder_with_default(img, [None, None, 3])
        T = render.import_model(model, t_input, t_input)
        acts = T(layer).eval()

    # We'll use ChannelReducer (a wrapper around scikit learn's factorization tools)
    # to apply Non-Negative Matrix factorization (NMF).

    nmf = ChannelReducer(n_groups, "PCA")
    print(layer, n_groups)
    spatial_factors = nmf.fit_transform(acts)[0].transpose(2, 0, 1).astype("float32")
    channel_factors = nmf._reducer.components_.astype("float32")

    # Let's organize the channels based on their horizontal position in the image

    x_peak = np.argmax(spatial_factors.max(1), 1)
    ns_sorted = np.argsort(x_peak)
    spatial_factors = spatial_factors[ns_sorted]
    channel_factors = channel_factors[ns_sorted]

    # And create a feature visualziation of each group

    param_f = lambda: param.image(80, batch=n_groups)
    obj = sum(objectives.direction(layer, channel_factors[i], batch=i)
              for i in range(n_groups))
    group_icons = render.render_vis(model, obj, param_f, verbose=False)[-1]

    # We'd also like to know about attribution
    #
    # First, let's turn each group into a vector over activations
    group_vecs = [spatial_factors[i, ..., None] * channel_factors[i]
                  for i in range(n_groups)]

    attrs = np.asarray([raw_class_group_attr(img, layer, attr_class, model, group_vecs)
                        for attr_class in attr_classes])

    gray_scale_groups = [skimage.color.rgb2gray(icon) for icon in group_icons]

    # Let's render the visualization!
    data = {
        "img": _image_url(img),
        "n_groups": n_groups,
        "spatial_factors": [_image_url(factor[..., None] / np.percentile(spatial_factors, 99) * [1, 0, 0]) for factor in
                            spatial_factors],
        "group_icons": [_image_url(icon) for icon in gray_scale_groups]
    }

    # with open('ng.pickle', 'wb') as handle:
    #     pickle.dump(data, handle, protocol=pickle.HIGHEST_PROTOCOL)
    # with open('./svelte_python/ng.pickle', 'rb') as p_file:
    #     data = pickle.load(p_file)

    generate_html('neuron_groups', data)
Example #3
0
def test_channel_reducer_trivial():
    array = np.zeros((10, 10, 10))
    for d in range(array.shape[-1]):
        array[:, :, d] = np.eye(10, 10)

    channel_reducer = ChannelReducer(n_components=2)
    channel_reducer.fit(array)
    reduced = channel_reducer.transform(array)

    assert reduced.shape == (10, 10, 2)
    # the hope here is that this was reduced to use only the first channel
    assert np.sum(reduced[:, :, 1]) == 0
Example #4
0
def test_channel_reducer_trivial():
  array = np.zeros((10,10,10), dtype=np.float32)
  for d in range(array.shape[-1]):
    array[:,:,d] = np.eye(10,10)

  channel_reducer = ChannelReducer(n_features=2)
  channel_reducer.fit(array)
  reduced = channel_reducer.transform(array)

  assert reduced.shape == (10,10,2)
  assert (reduced[:,:,0] == array[:,:,0]).all()
  assert (reduced[:,:,1] == 0).all()
Example #5
0
 def __init__(
     self,
     model,
     layer_name,
     obses,
     obses_full=None,
     features=10,
     *,
     attr_layer_name=None,
     attr_opts={"integrate_steps": 10},
 ):
     self.model = model
     self.layer_name = layer_name
     self.obses = obses
     self.obses_full = obses_full
     if self.obses_full is None:
         self.obses_full = obses
     self.features = features
     self.pad_h = 0
     self.pad_w = 0
     self.padded_obses = self.obses_full
     if self.features is None:
         self.reducer = None
     else:
         self.reducer = ChannelReducer(features)
     acts = get_acts(model, layer_name, obses)
     self.patch_h = self.obses_full.shape[1] / acts.shape[1]
     self.patch_w = self.obses_full.shape[2] / acts.shape[2]
     if self.reducer is None:
         self.acts_reduced = acts
         self.channel_dirs = np.eye(self.acts_reduced.shape[-1])
         self.transform = lambda acts: acts.copy()
         self.inverse_transform = lambda acts: acts.copy()
     else:
         if attr_layer_name is None:
             self.acts_reduced = self.reducer.fit_transform(acts)
         else:
             attrs = get_attr(model, attr_layer_name, layer_name, obses,
                              **attr_opts)
             attrs_signed = np.concatenate(
                 [np.maximum(0, attrs),
                  np.maximum(0, -attrs)], axis=0)
             self.reducer.fit(attrs_signed)
             self.acts_reduced = self.reducer.transform(acts)
         self.channel_dirs = self.reducer._reducer.components_
         self.transform = lambda acts: self.reducer.transform(acts)
         self.inverse_transform = lambda acts_r: ChannelReducer._apply_flat(
             self.reducer._reducer.inverse_transform, acts_r)
Example #6
0
def reduce_activations(acts: np.ndarray, reduction: str = 'NMF', dim: int = 6) -> np.ndarray:
    """
    Given the activations, perform the specified dimensionality reduction.

    Returns: Array of shape (LENGTH OF ACTS, DIM)
    """
    reducer = ChannelReducer(dim, reduction)
    if reduction == 'NMF':
        # NMF requires activations to be positive
        acts = get_positive_activations(acts)
    return reducer._reducer.fit_transform(acts)
Example #7
0
class LayerNMF:
    def __init__(
        self,
        model,
        layer_name,
        obses,
        obses_full=None,
        features=10,
        *,
        attr_layer_name=None,
        attr_opts={"integrate_steps": 10},
    ):
        self.model = model
        self.layer_name = layer_name
        self.obses = obses
        self.obses_full = obses_full
        if self.obses_full is None:
            self.obses_full = obses
        self.features = features
        self.pad_h = 0
        self.pad_w = 0
        self.padded_obses = self.obses_full
        if self.features is None:
            self.reducer = None
        else:
            self.reducer = ChannelReducer(features)
        acts = get_acts(model, layer_name, obses)
        self.patch_h = self.obses_full.shape[1] / acts.shape[1]
        self.patch_w = self.obses_full.shape[2] / acts.shape[2]
        if self.reducer is None:
            self.acts_reduced = acts
            self.channel_dirs = np.eye(self.acts_reduced.shape[-1])
            self.transform = lambda acts: acts.copy()
            self.inverse_transform = lambda acts: acts.copy()
        else:
            if attr_layer_name is None:
                self.acts_reduced = self.reducer.fit_transform(acts)
            else:
                attrs = get_attr(model, attr_layer_name, layer_name, obses,
                                 **attr_opts)
                attrs_signed = np.concatenate(
                    [np.maximum(0, attrs),
                     np.maximum(0, -attrs)], axis=0)
                self.reducer.fit(attrs_signed)
                self.acts_reduced = self.reducer.transform(acts)
            self.channel_dirs = self.reducer._reducer.components_
            self.transform = lambda acts: self.reducer.transform(acts)
            self.inverse_transform = lambda acts_r: ChannelReducer._apply_flat(
                self.reducer._reducer.inverse_transform, acts_r)

    def vis_traditional(
        self,
        feature_list=None,
        *,
        transforms=[transform.jitter(2)],
        l2_coeff=0.0,
        l2_layer_name=None,
    ):
        if feature_list is None:
            feature_list = list(range(self.acts_reduced.shape[-1]))
        try:
            feature_list = list(feature_list)
        except TypeError:
            feature_list = [feature_list]

        obj = sum([
            objectives.direction_neuron(self.layer_name,
                                        self.channel_dirs[feature],
                                        batch=feature)
            for feature in feature_list
        ])
        if l2_coeff != 0.0:
            assert (
                l2_layer_name is not None
            ), "l2_layer_name must be specified if l2_coeff is non-zero"
            obj -= objectives.L2(l2_layer_name) * l2_coeff
        param_f = lambda: param.image(64, batch=len(feature_list))
        return render.render_vis(self.model,
                                 obj,
                                 param_f=param_f,
                                 transforms=transforms)[-1]

    def pad_obses(self, *, expand_mult=1):
        pad_h = np.ceil(self.patch_h * expand_mult).astype(int)
        pad_w = np.ceil(self.patch_w * expand_mult).astype(int)
        if pad_h > self.pad_h or pad_w > self.pad_w:
            self.pad_h = pad_h
            self.pad_w = pad_w
            self.padded_obses = (np.indices((
                self.obses_full.shape[1] + self.pad_h * 2,
                self.obses_full.shape[2] + self.pad_w * 2,
            )).sum(axis=0) % 2)
            self.padded_obses = self.padded_obses * 0.25 + 0.75
            self.padded_obses = self.padded_obses.astype(self.obses_full.dtype)
            self.padded_obses = self.padded_obses[None, ..., None]
            self.padded_obses = self.padded_obses.repeat(
                self.obses_full.shape[0], axis=0)
            self.padded_obses = self.padded_obses.repeat(3, axis=-1)
            self.padded_obses[:, self.pad_h:-self.pad_h,
                              self.pad_w:-self.pad_w, :] = self.obses_full

    def get_patch(self, obs_index, pos_h, pos_w, *, expand_mult=1):
        left_h = self.pad_h + (pos_h - 0.5 * expand_mult) * self.patch_h
        right_h = self.pad_h + (pos_h + 0.5 * expand_mult) * self.patch_h
        left_w = self.pad_w + (pos_w - 0.5 * expand_mult) * self.patch_w
        right_w = self.pad_w + (pos_w + 0.5 * expand_mult) * self.patch_w
        slice_h = slice(int(round(left_h)), int(round(right_h)))
        slice_w = slice(int(round(left_w)), int(round(right_w)))
        return self.padded_obses[obs_index, slice_h, slice_w]

    def vis_dataset(self,
                    feature,
                    *,
                    subdiv_mult=1,
                    expand_mult=1,
                    top_frac=0.1):
        acts_h, acts_w = self.acts_reduced.shape[1:3]
        zoom_h = subdiv_mult - (subdiv_mult - 1) / (acts_h + 2)
        zoom_w = subdiv_mult - (subdiv_mult - 1) / (acts_w + 2)
        acts_subdiv = self.acts_reduced[..., feature]
        acts_subdiv = np.pad(acts_subdiv, [(0, 0), (1, 1), (1, 1)],
                             mode="edge")
        acts_subdiv = nd.zoom(acts_subdiv, [1, zoom_h, zoom_w],
                              order=1,
                              mode="nearest")
        acts_subdiv = acts_subdiv[:, 1:-1, 1:-1]
        if acts_subdiv.size == 0:
            raise RuntimeError(
                f"subdiv_mult of {subdiv_mult} too small for "
                f"{self.acts_reduced.shape[1]}x{self.acts_reduced.shape[2]} "
                "activations")
        poses = np.indices((acts_h + 2, acts_w + 2)).transpose((1, 2, 0))
        poses = nd.zoom(poses.astype(float), [zoom_h, zoom_w, 1],
                        order=1,
                        mode="nearest")
        poses = poses[1:-1, 1:-1, :] - 0.5
        with np.errstate(divide="ignore"):
            max_rep = np.ceil(
                np.divide(
                    acts_subdiv.shape[1] * acts_subdiv.shape[2],
                    acts_subdiv.shape[0] * top_frac,
                ))
        obs_indices = argmax_nd(acts_subdiv,
                                axes=[0],
                                max_rep=max_rep,
                                max_rep_strict=False)[0]
        self.pad_obses(expand_mult=expand_mult)
        patches = []
        patch_acts = np.zeros(obs_indices.shape)
        for i in range(obs_indices.shape[0]):
            patches.append([])
            for j in range(obs_indices.shape[1]):
                obs_index = obs_indices[i, j]
                pos_h, pos_w = poses[i, j]
                patch = self.get_patch(obs_index,
                                       pos_h,
                                       pos_w,
                                       expand_mult=expand_mult)
                patches[i].append(patch)
                patch_acts[i, j] = acts_subdiv[obs_index, i, j]
        patch_acts_max = patch_acts.max()
        opacities = patch_acts / (1 if patch_acts_max == 0 else patch_acts_max)
        for i in range(obs_indices.shape[0]):
            for j in range(obs_indices.shape[1]):
                opacity = opacities[i, j][None, None, None]
                opacity = opacity.repeat(patches[i][j].shape[0], axis=0)
                opacity = opacity.repeat(patches[i][j].shape[1], axis=1)
                patches[i][j] = np.concatenate([patches[i][j], opacity],
                                               axis=-1)
        return (
            np.concatenate(
                [
                    np.concatenate(patches[i], axis=1)
                    for i in range(len(patches))
                ],
                axis=0,
            ),
            obs_indices.tolist(),
        )

    def vis_dataset_thumbnail(self,
                              feature,
                              *,
                              num_mult=1,
                              expand_mult=1,
                              max_rep=None):
        if max_rep is None:
            max_rep = num_mult
        if self.acts_reduced.shape[0] < num_mult**2:
            raise RuntimeError(
                f"At least {num_mult ** 2} observations are required to produce"
                " a thumbnail visualization.")
        acts_feature = self.acts_reduced[..., feature]
        pos_indices = argmax_nd(acts_feature,
                                axes=[1, 2],
                                max_rep=max_rep,
                                max_rep_strict=True)
        acts_single = acts_feature[range(acts_feature.shape[0]),
                                   pos_indices[0], pos_indices[1]]
        obs_indices = np.argsort(-acts_single, axis=0)[:num_mult**2]
        coords = np.array(list(zip(*pos_indices)),
                          dtype=[("h", int), ("w", int)])[obs_indices]
        indices_order = np.argsort(coords, axis=0, order=("h", "w"))
        indices_order = indices_order.reshape((num_mult, num_mult))
        for i in range(num_mult):
            indices_order[i] = indices_order[i][np.argsort(
                coords[indices_order[i]], axis=0, order="w")]
        obs_indices = obs_indices[indices_order]
        poses = np.array(pos_indices).transpose()[obs_indices] + 0.5
        self.pad_obses(expand_mult=expand_mult)
        patches = []
        patch_acts = np.zeros((num_mult, num_mult))
        patch_shapes = []
        for i in range(num_mult):
            patches.append([])
            for j in range(num_mult):
                obs_index = obs_indices[i, j]
                pos_h, pos_w = poses[i, j]
                patch = self.get_patch(obs_index,
                                       pos_h,
                                       pos_w,
                                       expand_mult=expand_mult)
                patches[i].append(patch)
                patch_acts[i, j] = acts_single[obs_index]
                patch_shapes.append(patch.shape)
        patch_acts_max = patch_acts.max()
        opacities = patch_acts / (1 if patch_acts_max == 0 else patch_acts_max)
        patch_min_h = np.array([s[0] for s in patch_shapes]).min()
        patch_min_w = np.array([s[1] for s in patch_shapes]).min()
        for i in range(num_mult):
            for j in range(num_mult):
                opacity = opacities[i, j][None, None, None]
                opacity = opacity.repeat(patches[i][j].shape[0], axis=0)
                opacity = opacity.repeat(patches[i][j].shape[1], axis=1)
                patches[i][j] = np.concatenate([patches[i][j], opacity],
                                               axis=-1)
                patches[i][j] = patches[i][j][:patch_min_h, :patch_min_w]
        return (
            np.concatenate(
                [
                    np.concatenate(patches[i], axis=1)
                    for i in range(len(patches))
                ],
                axis=0,
            ),
            obs_indices.tolist(),
        )
Example #8
0
    def render_activation_grid_less_naive(self,
                                          img,
                                          layer="mixed4d",
                                          W=42,
                                          n_groups=6,
                                          subsample_factor=1,
                                          n_steps=256):
        # Get the activations
        with tf.Graph().as_default(), tf.Session() as sess:
            t_input = tf.placeholder("float32", [None, None, None, 3])
            T = render.import_model(self.model, t_input, t_input)
            acts = T(layer).eval({t_input: img[None]})[0]
        acts_flat = acts.reshape([-1] + [acts.shape[2]])
        N = acts_flat.shape[0]

        # The trick to avoiding "decoherence" is to recognize images that are
        # for similar activation vectors and
        if n_groups > 0:
            reducer = ChannelReducer(n_groups, "NMF")
            groups = reducer.fit_transform(acts_flat)
            groups /= groups.max(0)
        else:
            groups = np.zeros([])

        print(groups.shape)

        # The key trick to increasing memory efficiency is random sampling.
        # Even though we're visualizing lots of images, we only run a small
        # subset through the network at once. In order to do this, we'll need
        # to hold tensors in a tensorflow graph around the visualization process.
        with tf.Graph().as_default() as graph, tf.Session() as sess:
            # Using the groups, create a paramaterization of images that
            # partly shares paramters between the images for similar activation
            # vectors. Each one still has a full set of unique parameters, and could
            # optimize to any image. We're just making it easier to find solutions
            # where things are the same.
            group_imgs_raw = param.fft_image([n_groups, W, W, 3])
            unique_imgs_raw = param.fft_image([N, W, W, 3])
            opt_imgs = param.to_valid_rgb(tf.stack([
                0.7 * unique_imgs_raw[i] +
                0.5 * sum(groups[i, j] * group_imgs_raw[j]
                          for j in range(n_groups)) for i in range(N)
            ]),
                                          decorrelate=True)

            # Construct a random batch to optimize this step
            batch_size = 64
            rand_inds = tf.random_uniform([batch_size], 0, N, dtype=tf.int32)
            pres_imgs = tf.gather(opt_imgs, rand_inds)
            pres_acts = tf.gather(acts_flat, rand_inds)
            obj = objectives.Objective.sum([
                objectives.direction(layer, pres_acts[n], batch=n)
                for n in range(batch_size)
            ])

            # Actually do the optimization...
            T = render.make_vis_T(self.model, obj, param_f=pres_imgs)
            tf.global_variables_initializer().run()

            for i in range(n_steps):
                T("vis_op").run()
                if (i + 1) % (n_steps // 2) == 0:
                    show(pres_imgs.eval()[::4])

            vis_imgs = opt_imgs.eval()

        # Combine the images and display the resulting grid
        print("")
        vis_imgs_ = vis_imgs.reshape(list(acts.shape[:2]) + [W, W, 3])
        vis_imgs_cropped = vis_imgs_[:, :, 2:-2, 2:-2, :]
        show(np.hstack(np.hstack(vis_imgs_cropped)))
        return vis_imgs_cropped
def neuron_groups(imglist, filenamelist, layer, n_groups=6, attr_classes=None):
    # Compute activations
    filename = ''
    for f in filenamelist:
        filename += f
    with open('result/' + filename + '.html', 'a') as f:
        f.write('''<!DOCTYPE html>
                        <html>
                        <head >
                          <title>%s</title>
                              <script src='GroupWidget_1cb0e0d.js'></script>
                        </head>
                        <body>''' % (filename))
    for key, img in enumerate(imglist):
        if attr_classes is None:
            attr_classes = []
        with tf.Graph().as_default(), tf.Session():
            t_input = tf.placeholder_with_default(img, [None, None, 3])
            T = render.import_model(model, t_input, t_input)
            acts = T(layer).eval()

        # We'll use ChannelReducer (a wrapper around scikit learn's factorization tools)
        # to apply Non-Negative Matrix factorization (NMF).

        nmf = ChannelReducer(n_groups, "NMF")
        spatial_factors = nmf.fit_transform(acts)[0].transpose(
            2, 0, 1).astype("float32")
        channel_factors = nmf._reducer.components_.astype("float32")

        # Let's organize the channels based on their horizontal position in the image

        x_peak = np.argmax(spatial_factors.max(1), 1)
        ns_sorted = np.argsort(x_peak)
        spatial_factors = spatial_factors[ns_sorted]
        channel_factors = channel_factors[ns_sorted]

        # And create a feature visualziation of each group

        param_f = lambda: param.image(80, batch=n_groups)
        obj = sum(
            objectives.direction(layer, channel_factors[i], batch=i)
            for i in range(n_groups))
        group_icons = render.render_vis(model, obj, param_f, verbose=False)[-1]

        # We'd also like to know about attribution

        # First, let's turn each group into a vector over activations
        group_vecs = [
            spatial_factors[i, ..., None] * channel_factors[i]
            for i in range(n_groups)
        ]

        attrs = np.asarray([
            raw_class_group_attr(img, layer, attr_class, group_vecs)
            for attr_class in attr_classes
        ])

        print(attrs)

        # Let's render the visualization!

        with open('result/' + filename + '.html', 'a') as f:
            f.write('''  <main%s></main%s>
                          <script>
                            var app = new GroupWidget_1cb0e0d({
                              target: document.querySelector( 'main%s' ),''' %
                    (key, key, key))
            f.write('''data: {''')
            f.write('"img":"%s",\n' % str(_image_url(img)))
            f.write('"n_groups"' + ":" + str(n_groups) + ',\n')
            f.write('"spatial_factors"' + ":" + str([
                _image_url(factor[..., None] /
                           np.percentile(spatial_factors, 99) * [1, 0, 0])
                for factor in spatial_factors
            ]) + ',\n')
            f.write('"group_icons"' + ":" +
                    str([_image_url(icon) for icon in group_icons]) + ',\n')
            f.write('''} });''')
            f.write('''</script>''')

    with open('result/' + filename + '.html', 'a') as f:
        f.write('''</body></html >''')
    print(filename)