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)
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)
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
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()
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 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)
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(), )
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)