Подтвердить что ты не робот

Визуализация вывода сверточного слоя в тензорном потоке

Я пытаюсь визуализировать вывод сверточного слоя в тензорном потоке с помощью функции 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 разных ядра, поэтому я в основном перебираю различные карты функций здесь.

Как я могу их правильно изменить? Или есть другая вспомогательная функция, которую я мог бы использовать для включения этого вывода в сводку?

4b9b3361

Ответ 1

Я не знаю вспомогательной функции, но если вы хотите увидеть все фильтры, вы можете упаковать их в одно изображение с некоторыми причудливыми использованиями 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 = 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-порядке, по умолчанию.

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

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

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

Лично я предпочитаю np.einsum для причудливых переносов, для читабельности, но это еще не в tf пока.

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

в любом случае, теперь, когда пиксели расположены в правильном порядке, мы можем смело выровнять его в двумерный тензор:

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

попробуйте tf.image_summary, вы должны получить сетку из маленьких изображений.

Ниже приведено изображение того, что вы получаете, выполнив все перечисленные здесь шаги.

enter image description here

Ответ 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')

Ответ 3

вы можете попытаться получить изображение активации уровня свертки следующим образом:

    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)

Ответ 4

Я лично пытаюсь разбивать каждый 2d-фильтр на одно изображение.

Для этого -if я не ошибаюсь, так как я совершенно новичок в DL - Я узнал, что было бы полезно использовать depth_to_space, так как он принимает 4d-тензор

[batch, height, width, depth]

и производит вывод формы

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

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

Ответ 5

Другой способ, который я считаю очень простым, - это использование функции 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')

Например, ниже приведены входные данные (цветной кот) и выходные данные второго конвон-слоя в моей модели.below

Обратите внимание, что я знаю, что этот вопрос старый и есть более простые методы с Keras, но для людей, которые используют старую модель от других людей (таких как я), это может быть полезно.