基于DeepStream的CNN的可视化理解

时间:2022-04-16 03:25:46

  对CNN进行可视化是一项重要的工作,有助于理解深度学习模型的黑箱里面到底是什么东西。

有个著名的工具是:deep-visualization-toolbox里面还实现了对各种类别的展示,同时还有个遮挡的实验,令人印象深刻。

  此外,只用tensorflow的deepstream来学习一下CNN的模型到底都有哪些东西。代码可以看:https://github.com/tensorflow/tensorflow/blob/master/tensorflow/examples/tutorials/deepdream/deepdream.ipynb。

其官网介绍如下:

This directory contains Jupyter notebook that demonstrates a number of Convolutional Neural Network image generation techniques implemented with TensorFlow:

  • visualizing individual feature channels and their combinations to explore the space of patterns learned by the neural network (see GoogLeNet and VGG16 galleries)
  • embedding TensorBoard graph visualizations into Jupyter notebooks
  • producing high-resolution images with tiled computation (example)
  • using Laplacian Pyramid Gradient Normalization to produce smooth and colorful visuals at low cost
  • generating DeepDream-like images with TensorFlow

从官网说明可以看出:DeepStream主要用于查看现有谷歌基于imagenet进行建立模型的内部特征。并可以产生高精度的图像。

def render_deepdream(t_obj, img0=img_noise,
iter_n=10, step=1.5, octave_n=4, octave_scale=1.4):
t_score = tf.reduce_mean(t_obj) # defining the optimization objective
t_grad = tf.gradients(t_score, t_input)[0] # behold the power of automatic differentiation!

# split the image into a number of octaves
img = img0
octaves = []
for i in range(octave_n-1):
hw = img.shape[:2]
lo = resize(img, np.int32(np.float32(hw)/octave_scale))
hi = img-resize(lo, hw)
img = lo
octaves.append(hi)

# generate details octave by octave
for octave in range(octave_n):
if octave>0:
hi = octaves[-octave]
img = resize(img, hi.shape[:2])+hi
for i in range(iter_n):
g = calc_grad_tiled(img, t_grad)
img += g*(step / (np.abs(g).mean()+1e-7))
print('.',end = ' ')
clear_output()
showarray(img/255.0)
从上面的deepstream代码可以看出,针对某一个颜色通道,进行逐层展示,其算法的基本介绍如下。

Making the "dream" images is very simple. Essentially it is just a gradient ascent process that tries to maximize the L2 norm of activations of a particular DNN layer. Here are a few simple tricks that we found useful for getting good images:

  • offset image by a random jitter
  • normalize the magnitude of gradient ascent steps
  • apply ascent across multiple scales (octaves)

First we implement a basic gradient ascent step function, applying the first two tricks:

当然DeepDream的测试核心步骤如下:

if __name__ == '__main__':    
# creating TensorFlow session and loading the model
graph = tf.Graph()
sess = tf.InteractiveSession(graph=graph)
with tf.gfile.FastGFile(model_fn, 'rb') as f:
graph_def = tf.GraphDef()
graph_def.ParseFromString(f.read())
t_input = tf.placeholder(np.float32, name='input') # define the input tensor
imagenet_mean = 117.0
t_preprocessed = tf.expand_dims(t_input-imagenet_mean, 0)
tf.import_graph_def(graph_def, {'input':t_preprocessed})

layers = [op.name for op in graph.get_operations() if op.type=='Conv2D' and 'import/' in op.name]
print(layers)
feature_nums = [int(graph.get_tensor_by_name(name+':0').get_shape()[-1]) for name in layers]

print('Number of layers', len(layers))
print('Total number of feature channels:', sum(feature_nums))

# Picking some internal layer. Note that we use outputs before applying the ReLU nonlinearity
# to have non-zero gradients for features with negative initial activations.
layer = 'mixed4d_3x3_bottleneck_pre_relu'
channel = 139 # picking some feature channel to visualize

# start with a gray image with a little noise
img_noise = np.random.uniform(size=(224,224,3)) + 100.0

resize = tffunc(np.float32, np.int32)(resize)


# render_naive(T(layer)[:,:,:,channel], img_noise)
# render_multiscale(T(layer)[:,:,:,channel], img_noise)
img0 = PIL.Image.open('images/tiger.jpg')
img0 = np.float32(img0)
# render_deepdream(tf.square(T('mixed4c')), img0)
render_deepdream(T(layer)[:,:,:,139], img0)

上面可以基于某个图片上进行绘制逐层的特征抽象,默认只绘制4层,如139层为花朵的特征层。其逐层展示结果如下:

基于DeepStream的CNN的可视化理解基于DeepStream的CNN的可视化理解

基于DeepStream的CNN的可视化理解

基于DeepStream的CNN的可视化理解


这种展示效果还是非常好的。当然看到说可以对上面的特征层可以再进行排序的,可能会产生意想不到的效果。以后有时间再测试一下。