2015-11-19 128 views
20

我試圖使用函數tf.image_summary可視化張量流中卷積層的輸出。在其他情況下,我已經成功地使用了它(例如,可視化輸入圖像),但在正確地重新調整輸出方面有一些困難。我有以下CONV層:可視化張量流中卷積層的輸出

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個不同的內核,所以我基本上在這裏通過不同的功能映射進行切片。

我該如何正確重塑它們?或者是否有另一個輔助函數可用於在彙總中包含此輸出?

回答

23

我不知道輔助功能,但如果你想看到所有的過濾器,你可以將它們打包成一個圖像,並使用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=256

所以,channels=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) 

圍繞然後重塑,從而代替32個頻道你有4×8渠道,讓打電話給他們cy=4cx=8

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

現在棘手的部分。 tf似乎返回C順序的結果,numpy的默認值。

在列出第二個像素的通道(遞增ix)之前,當前順序如果展平,將列出第一個像素的所有通道(迭代cxcy)。跨越像素行(ix),然後遞增到下一行(iy)。

我們想要在網格中放置圖像的順序。 因此,當您沿着通道行(cx)行進時,您沿着一排圖像(ix)行進,當您觸碰到一排通道時,您將跳到圖像中的下一行(iy),當您用完或圖像中的行增加到下一行通道(cy)。所以:

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

個人而言,我更喜歡np.einsum花式轉置,爲便於閱讀,但它不是在tfyet

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

感謝您的回答,我被困在轉置部分。我結束了使用[稍微不同的版本](https://gist.github.com/panmari/4622b78ce21e44e2d69c),因爲我只看到前幾個卷積(我不需要所有的卷積格)。網格在張量板上很難檢查。 – panmari

+1

在我看來,你寫的最後fy和fx實際上是cy和cx – jean

+1

什麼是更多,你只能通過4D張量到'tf.image_summary',所以你將不得不重塑'V = tf.reshape(V,( 1,4 * 256,8 * 256,1))' – jean

2

如果有人想「跳」到numpy的和可視化「有」這裏是如何同時顯示Weightsprocessing result一個例子。所有轉換均基於mdaoust的prev回答。

# 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') 
0

,你可以嘗試讓卷積層激活形象是這樣的:

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

這得到一個豎條紋與垂直連接在一起的所有圖像。

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) 
0

我親自嘗試,平鋪在一個單一的形象連用2d過濾:如果你想讓他們補齊(在我的情況RELU激活的墊用白線)

這樣做 - 如果我不是非常錯誤的,因爲我是很新的DL-我發現,它可幫助開拓depth_to_space功能,因爲它需要一個四維張量

[batch, height, width, depth]

併產生形狀

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

凡BLOCK_SIZE爲輸出圖像中的「塊」的數目的輸出。對此的唯一限制是深度應該是block_size的平方,這是一個整數,否則它不能「正確」填充結果圖像。 一個可能的解決方案可能是將輸入張量的深度填充到方法所接受的深度,但我仍然沒有嘗試過。