(Es tut mir leid für den Nischeninhalt.)
Als ich einen bestimmten GAN-Code (Generative Adversarial Networks), der in ** Theano ** + ** Lasagne ** geschrieben wurde, nach ** TensorFlow ** portierte, stieß ich auf etwas namens "lasagne.layers.NINLayer". Es war. Wenn Sie sich die Lasagne-Dokumentation ansehen,
Network-in-network layer. Like DenseLayer, but broadcasting across all trailing dimensions beyond the 2nd. This results in a convolution operation with filter size 1 on all trailing dimensions. Any number of trailing dimensions is supported, so NINLayer can be used to implement 1D, 2D, 3D, ... convolutions.
"Eine Schicht wie eine eng gekoppelte Schicht, die auf Bestellungen jenseits der zweiten Dimension" sendet "." Aus dem Namen Network-in-Network-Schicht habe ich mich zunächst fertig gemacht, möchte es aber gerne vorstellen, da es sehr einfach war, in TensorFlow zu schreiben.
(Programmierumgebung: - Python: 3.5.2 - Theano: 0.9.0 - Lasagne: 0.2.dev1 - TensorFlow: 1.2.0 )
Da die Operation in der Erläuterung des Dokuments nicht klar war, habe ich es mit kleinen Daten getestet.
import numpy as np
import theano
import theano.tensor as T
import lasagne
from lasagne.layers import InputLayer, NINLayer
# variables
x = T.tensor4('x')
y = T.matrix('y')
# shared variable
w_np= np.array([[1., 2., 3], [2., 2., 2.]], dtype=np.float32)
ws = theano.shared(w_np, name='w')
# layers
l_in = InputLayer((1, 2, 5, 5)) # image size = 3
l1 = NINLayer(l_in, num_units=3, W=ws, b=None,
nonlinearity=None)
l_in.input_var = x
y = lasagne.layers.get_output(l1)
# theano function
mylayer = theano.function(
inputs=[x],
outputs=y,
allow_input_downcast=True
)
x_np = np.ones([1, 2, 5, 5]) * 0.1
y_np = mylayer(x_np)
y_np = np.asarray(y_np)
print('x_np.shape = ', x_np.shape)
print('x_np = \n', x_np)
print(' ')
print('y_np.shape = ', y_np.shape)
print('y_np = \n', y_np)
Das Folgende ist die Ausgabe des Berechnungsergebnisses.
x_np.shape = (1, 2, 5, 5)
x_np =
[[[[ 0.1 0.1 0.1 0.1 0.1]
[ 0.1 0.1 0.1 0.1 0.1]
[ 0.1 0.1 0.1 0.1 0.1]
[ 0.1 0.1 0.1 0.1 0.1]
[ 0.1 0.1 0.1 0.1 0.1]]
[[ 0.1 0.1 0.1 0.1 0.1]
[ 0.1 0.1 0.1 0.1 0.1]
[ 0.1 0.1 0.1 0.1 0.1]
[ 0.1 0.1 0.1 0.1 0.1]
[ 0.1 0.1 0.1 0.1 0.1]]]]
y_np.shape = (1, 3, 5, 5)
y_np =
[[[[ 0.30000001 0.30000001 0.30000001 0.30000001 0.30000001]
[ 0.30000001 0.30000001 0.30000001 0.30000001 0.30000001]
[ 0.30000001 0.30000001 0.30000001 0.30000001 0.30000001]
[ 0.30000001 0.30000001 0.30000001 0.30000001 0.30000001]
[ 0.30000001 0.30000001 0.30000001 0.30000001 0.30000001]]
[[ 0.40000001 0.40000001 0.40000001 0.40000001 0.40000001]
[ 0.40000001 0.40000001 0.40000001 0.40000001 0.40000001]
[ 0.40000001 0.40000001 0.40000001 0.40000001 0.40000001]
[ 0.40000001 0.40000001 0.40000001 0.40000001 0.40000001]
[ 0.40000001 0.40000001 0.40000001 0.40000001 0.40000001]]
[[ 0.5 0.5 0.5 0.5 0.5 ]
[ 0.5 0.5 0.5 0.5 0.5 ]
[ 0.5 0.5 0.5 0.5 0.5 ]
[ 0.5 0.5 0.5 0.5 0.5 ]
[ 0.5 0.5 0.5 0.5 0.5 ]]]]
Wenn Sie sich die obigen Eingabe- / Ausgabedaten ansehen, können Sie die Funktion der Ebene verstehen. Geben Sie alle Pixeldaten ein, die in zwei Dimensionen und Gewicht in Kanalrichtung (in Bezug auf die Tiefe) erweitert wurden. Im obigen Beispiel ist w = [[1., 2., 3], [2., 2., 2] Es ist eine Berechnung, mit der multipliziert werden muss.]]. Da der Eingang in Form von 2 Kanälen und das Gewicht in Form von [2 x 3] vorliegt, beträgt der Ausgang 3 Kanäle. Im obigen Code sind die Eingabedaten alle ... 0.1, aber da es sich tatsächlich um Bilddaten handelt, kann ein beliebiger Wert eingegeben werden.
Beachten Sie, dass in "Theano" die Bilddaten als "Kanal 1" behandelt werden (tatsächlich kommt der Kanal zur Vereinfachung der Stapelverarbeitung an zweiter Stelle) und in "TensorFlow" "Kanal zuletzt". Dann habe ich versucht, es zu verpflanzen.
# NIN (network in network) like function
def lasagne_nin_like(x, w):
'''
args.:
input shape: [None, pixel, pixel, input_channel]
output shape: [None, pixel, pixel, output_channel]
'''
input_ch = tf.shape(x)[-1] # eq. 2
output_ch = tf.shape(w)[-1] # eq. 3
net = tf.reshape(x, [-1, input_ch])
net = tf.matmul(net, w)
y = tf.reshape(net, [-1, 5, 5, output_ch])
return y
y = lasagne_nin_like(x, W)
Alles, was Sie tun müssen, ist, den Eingabewert für die Anzahl der Kanäle zu belassen und daraus eine flache Form "tf.reshape ()" zu machen. Nach der Matrixmultiplikation kehren Sie in die ursprüngliche Form zurück. Es war einfacher als erwartet zu portieren.
Der gesamte TensorFlow-Code lautet wie folgt.
import numpy as np
import tensorflow as tf
# tensorflow placeholders
x = tf.placeholder(tf.float32, [None, 5, 5, 2])
# shared variable
w_np= np.array([[1., 2., 3], [2., 2., 2.]])
W = tf.Variable(w_np, dtype=tf.float32)
# NIN (network in network) like function
def lasagne_nin_like(x, w):
'''
args.:
input shape: [None, pixel, pixel, input_channel]
output shape: [None, pixel, pixel, output_channel]
'''
input_ch = tf.shape(x)[-1] # eq. 2
output_ch = tf.shape(w)[-1] # eq. 3
net = tf.reshape(x, [-1, input_ch])
net = tf.matmul(net, w)
y = tf.reshape(net, [-1, 5, 5, output_ch])
return y
y = lasagne_nin_like(x, W)
# tensorflow session
init = tf.global_variables_initializer()
sess = tf.InteractiveSession()
sess.run(init)
x_np = np.ones([1, 5, 5, 2], dtype=np.float32) * 0.1
y_np = sess.run(y, feed_dict={x: x_np})
print('x_np.shape = ', x_np.shape)
# output should be transposed to compare theano's result.
#Translokation des 4D-Tensors zum Vergleich der Berechnungsergebnisse(ch-last -> ch-1st)ich mache
y_np = np.transpose(y_np, (0, 3, 1, 2))
print('y_np.shape = ', y_np.shape)
print('y_np = ', y_np)
Die Situation ist wie sie ist: "Es ist einfacher zu produzieren als Sie denken." Als Grund für die einfache Portierung wird angenommen, dass TensorFlow der "Channel-Last" -Regel folgt. Auf der anderen Seite hatte Theano + Lasagne den Nachteil, dass die Daten nicht in einer Zeile (basierend auf dem Kanal) abgeflacht werden konnten, sodass möglicherweise lasagne.layers.NINLayer erstellt wurde.
(Der Titel "Porting NIN Layer" war ein ziemlich übertriebener Titel ...)