2015-11-19 6 views
20

Ich versuche, die Ausgabe einer Faltungsschicht in tensorflow mit der Funktion tf.image_summary sichtbar zu machen. Ich verwende es bereits erfolgreich in anderen Fällen (z. B. Visualisierung des Eingangsbildes), habe aber Schwierigkeiten, die Ausgabe hier korrekt zu gestalten. Ich habe folgende konv Schicht:Visualizing Ausgabe von Faltungsschicht in 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) 

So ist die Ausgabe von h_conv1 würde [-1, img_size, img_size, 32] die Form haben. Nur die Verwendung von tf.image_summary("first_conv", tf.reshape(h_conv1, [-1, img_size, img_size, 1])) berücksichtigt nicht die 32 verschiedenen Kernel, so dass ich im Grunde durch verschiedene Feature-Maps hier durchschneiden.

Wie kann ich sie richtig umformen? Oder gibt es eine andere Hilfsfunktion, die ich verwenden könnte, um diese Ausgabe in die Zusammenfassung aufzunehmen?

Antwort

23

Ich weiß nicht, eine Hilfsfunktion, aber wenn Sie alle Filter sehen möchten, können Sie sie in ein Bild mit einigen ausgefallenen Anwendungen von packen.

Also, wenn Sie einen Tensor, die in diesem Beispiel ix = 256, iy=256, images x ix x iy x channels

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

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

So ist channels=32

erste Scheibe aus 1 Bild, und entfernen Sie die image Dimension

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

Next um das Bild, das Sie haben 4x8 Kanäle

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

Dann umformen, so dass anstelle von 32 Kanälen ein paar Pixel Nullen hinzufügen, läßt sie cy=4 und cx=8 nennen.

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

Jetzt der schwierige Teil. tf scheint Ergebnisse in C-Reihenfolge, numpy Standard zurückgegeben.

Der aktuelle Auftrag, wenn abgeflacht, würden alle Kanäle für den ersten Bildpunkt-Liste (iterieren cx und cy), bevor die Kanäle des zweiten Pixels Auflistung (Inkrementieren ix). Gehen Sie über die Pixelreihen (ix), bevor Sie zur nächsten Zeile wechseln (iy).

Wir wollen die Reihenfolge, die die Bilder in einem Raster legen würde. So gehen Sie über eine Reihe eines Bildes (ix), bevor Sie entlang der Reihe von Kanälen (cx), wenn Sie das Ende der Reihe von Kanälen treten Sie Schritt zur nächsten Zeile im Bild (iy) und wenn Sie Run out oder Zeilen in dem Bild, das Sie in die nächste Zeile der Kanäle (cy) erhöhen. so:

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

Persönlich bevorzuge ich np.einsum für Phantasie transponiert, um Lesbarkeit zu verbessern, aber es ist nicht in tfyet.

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

sowieso, jetzt, da die Pixel in der richtigen Reihenfolge sind, können wir sicher in ein 2D-Tensor abflachen:

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

versuchen tf.image_summary auf, dass, sollten Sie ein Raster aus kleinen Bildern bekommen.

Unten ist ein Bild davon, was man bekommt, nachdem man alle Schritte hier verfolgt hat.

enter image description here

+1

Danke für Ihre Antwort, ich war auf Transpose Teil stecken. Ich benutze eine [etwas andere Version] (https://gist.github.com/panmari/4622b78ce21e44e2d69c), da ich damit einverstanden bin, nur die ersten paar Windungen zu sehen (ich brauche nicht alle zusammen in einem Gitter). Das Gitter ist auf dem Tensorboard kaum zu prüfen. – panmari

+1

Es scheint mir, dass die letzten fy und fx, die Sie geschrieben haben, tatsächlich cy und cx sind – jean

+1

Was mehr ist, können Sie nur 4D Tensor zu 'tf.image_summary' übergeben, so müssen Sie' V = tf.reshape umformen (V, (1,4 * 256,8 * 256,1)) ' – jean

2

Falls jemand möchte „springen“ numpy und zu visualisieren „da“ ist hier ein Beispiel, wie beide Weights anzuzeigen und processing result. Alle Transformationen basieren auf der vorherigen Antwort von 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

Sie können versuchen, Faltung Schicht Aktivierung Bild auf diese Weise zu erhalten:

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

diese erhält man vertikale Streifen mit allen vertikal verketteten Bilder.

, wenn man sie gepolstert wollen (in meinem Fall von relu Aktivierungen Pad mit weißer Linie):

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

ich persönlich Kachel versuchen, jeden 2d-Filter in einem einzigen Bild.

Dafür tun -wenn ich nicht sehr irre, da ich ganz neu bin DL- Ich fand heraus, dass es hilfreich sein könnte, die depth_to_space Funktion zu nutzen, da es einen 4d Tensor nimmt

[batch, height, width, depth]

und erzeugt eine Ausgangsform

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

block_size Wo die Anzahl von "Kacheln" in dem Ausgabebild ist. Die einzige Einschränkung hierbei ist, dass die Tiefe das Quadrat von block_size sein sollte, das eine Ganzzahl ist, andernfalls kann das resultierende Bild nicht korrekt "gefüllt" werden. Eine mögliche Lösung könnte sein, die Tiefe des Eingangstensors bis zu einer Tiefe aufzufüllen, die von der Methode akzeptiert wird, aber das habe ich noch nicht ausprobiert.

Verwandte Themen