2015-11-19 5 views
20

Я пытаюсь представить результат сверточного слоя в тензорном потоке, используя функцию tf.image_summary. Я уже успешно использую его в других случаях (например, визуализируя входное изображение), но у меня есть некоторые трудности с изменением результата здесь. У меня есть следующие усл слой:Визуализация вывода сверточного слоя в тензорном потоке

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 х ix х iy х channels

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

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

Таким образом, в этом примере ix = 256, iy=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 каналов у вас есть 4x8 каналы, позволяет называть их cy=4 и cx=8.

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

Теперь сложная часть. tf, похоже, возвращает результаты в C-порядке, по умолчанию numpy.

Текущий порядок, если уплощенный, можно было бы перечислить все каналы для первого пикселя (итераций по cx и cy), прежде чем списку каналов второго пиксела (приращение ix). Переход по строкам пикселей (ix) до приращения в следующую строку (iy).

Мы хотим, чтобы заказ, который выкладывал изображения в сетке. Итак, вы переходите по строке изображения (ix), прежде чем ступить по ряду каналов (cx), когда вы попадаете в конец ряда каналов, вы переходите к следующей строке на изображении (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 и визуализировать «там» вот пример того, как отображать как Weights и processing 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') 
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-фильтр в одном изображении.

Для делать это -если я не очень ошибаюсь, так как я совершенно новой для Д.Л. я узнал, что это может быть полезно использовать функцию depth_to_space, так как он принимает 4d тензор

[batch, height, width, depth]

и производит выходной формы

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

Где block_size это количество «плитки» в выходном изображении. Единственным ограничением для этого является то, что глубина должна быть квадратом block_size, который является целым числом, иначе он не сможет «правильно заполнить» результирующее изображение. Возможное решение может заключаться в заполнении глубины входного тензора до глубины, которая принимается методом, но я не могу этого сделать.