可视化张量流中卷积层的输出

时间:2015-11-19 11:14:26

标签: tensorflow conv-neural-network

我正在尝试使用函数tf.image_summary在tensorflow中可视化卷积层的输出。我已经在其他情况下成功使用它(例如可视化输入图像),但是在这里正确地重塑输出有一些困难。我有以下转换层:

img_size = 256
x_image = tf.reshape(x, [-1,img_size, img_size,1], "sketch_image")

W_conv1 = weight_variable([5, 5, 1, 32])
b_conv1 = bias_variable([32])

h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)

因此h_conv1的输出形状为[-1, img_size, img_size, 32]。只使用tf.image_summary("first_conv", tf.reshape(h_conv1, [-1, img_size, img_size, 1]))不考虑32个不同的内核,所以我基本上在这里切换不同的功能图。

我怎样才能正确地重塑它们?或者是否有另一个帮助函数可用于在摘要中包含此输出?

5 个答案:

答案 0 :(得分:33)

我不知道辅助功能,但是如果你想看到所有过滤器,你可以将它们打包成一张图片,并使用tf.transpose的一些奇特用途。

因此,如果您的张量为images x ix x iy x channels

>>> V = tf.Variable()
>>> print V.get_shape()

TensorShape([Dimension(-1), Dimension(256), Dimension(256), Dimension(32)])

因此,在此示例中ix = 256iy=256channels=32

首先切掉1张图片,然后移除image尺寸

V = tf.slice(V,(0,0,0,0),(1,-1,-1,-1)) #V[0,...]
V = tf.reshape(V,(iy,ix,channels))

接下来在图像周围添加几个零填充像素

ix += 4
iy += 4
V = tf.image.resize_image_with_crop_or_pad(image, iy, ix)

然后重新塑造,以便使用4x8频道而不是32个频道,让我们称呼cy=4cx=8

V = tf.reshape(V,(iy,ix,cy,cx)) 

现在是棘手的部分。 tf似乎以C顺序返回结果,numpy的默认值。

当前顺序(如果展平)将列出第一个像素的所有通道(迭代cxcy),然后列出第二个像素的通道(递增ix )。在递增到下一行(ix)之前,遍历像素行(iy)。

我们想要将图像布置在网格中的顺序。 因此,在沿着一行通道(ix)行进之前,你会看到一行图像(cx),当你到达通道行的末尾时,你会走到下一行。图像(iy),当你在图像中用完或行时,你会增加到下一行通道(cy)。这样:

V = tf.transpose(V,(2,0,3,1)) #cy,iy,cx,ix

我个人更喜欢np.einsum用于花哨的转置,以提高可读性,但它不在tf yet中。

newtensor = np.einsum('yxYX->YyXx',oldtensor)

无论如何,既然像素的顺序正确,我们可以安全地将其压平成2d张量:

# image_summary needs 4d input
V = tf.reshape(V,(1,cy*iy,cx*ix,1))

尝试tf.image_summary,你应该得到一个小图像网格。

下面是按照此处的所有步骤后获得的图像。

enter image description here

答案 1 :(得分:2)

如果有人想“跳”到numpy并想象“那里”,这里有一个如何显示Weightsprocessing result的示例。所有转换均基于mdaoust的常见答案。

# to visualize 1st conv layer Weights
vv1 = sess.run(W_conv1)

# to visualize 1st conv layer output
vv2 = sess.run(h_conv1,feed_dict = {img_ph:x, keep_prob: 1.0})
vv2 = vv2[0,:,:,:]   # in case of bunch out - slice first img


def vis_conv(v,ix,iy,ch,cy,cx, p = 0) :
    v = np.reshape(v,(iy,ix,ch))
    ix += 2
    iy += 2
    npad = ((1,1), (1,1), (0,0))
    v = np.pad(v, pad_width=npad, mode='constant', constant_values=p)
    v = np.reshape(v,(iy,ix,cy,cx)) 
    v = np.transpose(v,(2,0,3,1)) #cy,iy,cx,ix
    v = np.reshape(v,(cy*iy,cx*ix))
    return v

# W_conv1 - weights
ix = 5  # data size
iy = 5
ch = 32   
cy = 4   # grid from channels:  32 = 4x8
cx = 8
v  = vis_conv(vv1,ix,iy,ch,cy,cx)
plt.figure(figsize = (8,8))
plt.imshow(v,cmap="Greys_r",interpolation='nearest')

#  h_conv1 - processed image
ix = 30  # data size
iy = 30
v  = vis_conv(vv2,ix,iy,ch,cy,cx)
plt.figure(figsize = (8,8))
plt.imshow(v,cmap="Greys_r",interpolation='nearest')

答案 2 :(得分:0)

您可以尝试以这种方式获取卷积层激活图像:

    h_conv1_features = tf.unpack(h_conv1, axis=3)
    h_conv1_imgs = tf.expand_dims(tf.concat(1, h_conv1_features_padded), -1)

这会得到一个垂直条纹,所有图像都是垂直连接的。

如果你想要它们填充(在我的情况下relu激活填充白线):

    h_conv1_features = tf.unpack(h_conv1, axis=3)
    h_conv1_max = tf.reduce_max(h_conv1)
    h_conv1_features_padded = map(lambda t: tf.pad(t-h_conv1_max, [[0,0],[0,1],[0,0]])+h_conv1_max, h_conv1_features)
    h_conv1_imgs = tf.expand_dims(tf.concat(1, h_conv1_features_padded), -1)

答案 3 :(得分:0)

我个人尝试在单个图像中平铺每个2d滤镜。

为了做到这一点 - 如果我不是非常错误,因为我对DL很新 - 我发现利用depth_to_space函数可能会有所帮助,因为它采用4d张量

[batch, height, width, depth]

并生成形状

的输出

[batch, height*block_size, width*block_size, depth/(block_size*block_size)]

其中block_size是输出图像中“tiles”的数量。唯一的限制是深度应该是block_size的平方,这是一个整数,否则它不能正确“填充”生成的图像。 一个可能的解决方案可能是将输入张量的深度填充到方法所接受的深度,但我没有尝试过这个。

答案 4 :(得分:0)

我认为很容易的另一种方法是使用get_operation_by_name函数。我很难用其他方法可视化图层,但这对我有所帮助。

#first, find out the operations, many of those are micro-operations such as add etc.
graph = tf.get_default_graph()
graph.get_operations()

#choose relevant operations
op_name = '...' 
op = graph.get_operation_by_name(op_name)
out = sess.run([op.outputs[0]], feed_dict={x: img_batch, is_training: False}) 
#img_batch is a single image whose dimensions are (1,n,n,1). 

# out is the output of the layer, do whatever you want with the output
#in my case, I wanted to see the output of a convolution layer
out2 = np.array(out)
print(out2.shape)

# determine, row, col, and fig size etc.
for each_depth in range(out2.shape[4]):
    fig.add_subplot(rows, cols, each_depth+1)
    plt.imshow(out2[0,0,:,:,each_depth], cmap='gray')

例如下面是我模型中第二个conv层的输入(彩色猫)和输出。below

请注意,我知道这个问题很旧,使用Keras的方法更简单,但对于使用其他人的旧模型的人(例如我),这可能会有用。