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