Ich habe ein undokumentiertes Verhalten bezüglich des Namensverhaltens in benutzerdefinierten Ebenen von tf.keras gefunden. Lassen Sie es mich wissen. Der hier erwähnte "Variablenname" ist nicht der Variablenname in der Python-Syntax, sondern der Name (als Argument erforderlich), der der Tensorflow-Variablen (tf.Variable) gegeben wird.
Vor dem empfohlenen Schreiben werde ich ein wenig über Variablennamen erklären.
Es ist nicht my.v1 oder self.v2 im folgenden Beispielcode, sondern my_variable1 oder my_variable2.
import tensorflow as tf
#Beispielcode für benutzerdefinierte Ebenen
#Selbstgemachte vollständig verbundene Schicht
class MyLayer(tf.keras.layers.Layer):
def __init__(self, output_dim):
super().__init__()
self.output_dim = output_dim
#Bias Begriff
#Dies hängt nicht von der Größe der Eingabedaten ab
self.v1 = self.add_weight(name='my_variable1', shape=[output_dim])
def build(self, input_shape):
#affine Matrix
#Hängt von der Größe der Eingabedaten ab
self.v2 = self.add_weight(name='my_variable2', shape=[input_shape[1], self.output_dim])
self.built = True
def call(self, inputs, **kwargs):
return tf.matmul(inputs, self.v2) + self.v1
Die Inhalte hier sind die Inhalte im offiziellen Tutorial.
Lassen Sie es uns tatsächlich ausführen und überprüfen.
model = MyLayer(output_dim=3)
#Die Erstellungsmethode wird ausgeführt, wenn Sie zum ersten Mal Daten eingeben. Geben Sie daher die entsprechenden Daten ein
x = tf.random.normal(shape=(3, 5))
y = model(x)
print(model.trainable_variables)
↓ Dies ist der Name
[<tf.Variable 'my_variable1:0' shape=(3,) dtype=float32, numpy=array([-0.56484747, 0.00200152, 0.42238712], dtype=float32)>,
↓ Dies ist der Name
<tf.Variable 'my_layer/my_variable2:0' shape=(5, 3) dtype=float32, numpy=
array([[ 0.47857696, -0.04394728, 0.31904382],
[ 0.37552172, 0.22522384, 0.07408607],
[-0.74956644, -0.61549807, -0.41261673],
[ 0.4850598 , -0.45188528, 0.56900233],
[-0.39462167, 0.40858668, -0.5422235 ]], dtype=float32)>]
my_variable1: 0
und my_layer / my_variable2: 0
.
Es gibt noch etwas Besonderes, aber ich habe bestätigt, dass die Variablennamen my_variable1 bzw. my_variable2 sind, also ist es OK.
Ist es richtig?
Fahren wir mit dem vorherigen Beispiel fort.
#Wenn Sie Ihre eigenen Ebenen stapeln
model = tf.keras.Sequential([
MyLayer(3),
MyLayer(3),
MyLayer(3)
])
↓
[<tf.Variable 'my_variable1:0' shape=(3,) dtype=float32, (Abkürzung)>,
<tf.Variable 'sequential/my_layer_1/my_variable2:0' shape=(5, 3) dtype=float32, (Abkürzung))>,
<tf.Variable 'my_variable1:0' shape=(3,) dtype=float32, (Abkürzung)>,
<tf.Variable 'sequential/my_layer_2/my_variable2:0' shape=(3, 3) dtype=float32, (Abkürzung)>,
<tf.Variable 'my_variable1:0' shape=(3,) dtype=float32, (Abkürzung)>,
<tf.Variable 'sequential/my_layer_3/my_variable2:0' shape=(3, 3) dtype=float32, (Abkürzung)]
my_variable1 ist voll (weint). Nicht zu unterscheiden.
Als ich ein Histogramm von Variablen auf Tensorboard zeichnete, stießen die Namen aufeinander und ich konnte den Grund nicht verstehen.
class MyLayer(tf.keras.layers.Layer):
def __init__(self, output_dim):
super().__init__()
self.output_dim = output_dim
def build(self, input_shape):
#Bias Begriff
#Dies hängt nicht von der Größe der Eingabedaten ab
self.v1 = self.add_weight(name='my_variable1', shape=[output_dim])
#affine Matrix
#Hängt von der Größe der Eingabedaten ab
self.v2 = self.add_weight(name='my_variable2', shape=[input_shape[1], self.output_dim])
self.built = True
def call(self, inputs, **kwargs):
return tf.matmul(inputs, self.v2) + self.v1
Deklarieren Sie einfach alle Variablen in der Erstellungsmethode.
Da Tensorflow auch durch Ausführen nach Version 2 definiert wird, kann es meiner Meinung nach erst gelöst werden, wenn zuerst die Modell- und Ebenenreihenfolge ausgeführt wird. Aus diesem Grund denke ich, dass es einen großen Unterschied zwischen der \ _ \ _ init__ -Methode und der Biuld-Methode gibt.
Übrigens sind tf.keras.layers.Dense usw. alle in der Erstellungsmethode deklariert, sodass Sie sie sicher verwenden können.
Wenn Sie eine Variable in einer benutzerdefinierten Ebene deklarieren, müssen Sie sie in der Erstellungsmethode deklarieren. Deklarieren Sie nicht in der Methode \ _ \ _ init__.
Erläuterung des Verhaltens der Namensverarbeitung
Es wird automatisch gemäß den Tensorflow-Spezifikationen hinzugefügt. Bei der Ausführung auf einer Multi-GPU wird für jede GPU eine Kopie der Variablen erstellt, sodass jede in dieser Reihenfolge mit 0, 1, 2, ... nummeriert ist. Die technischen Daten hier sind die gleichen wie in Version 1.
In Version 2 können Sie dies mit tf.distribute.MirroredStrategy usw. überprüfen, indem Sie dasselbe wie oben mit mehreren GPUs tun.
my_layer ist der Standardname, wenn Sie MyLayer nicht explizit benannt haben. Der Klassenname wird automatisch in einen Schlangenfall konvertiert.
Wenn im zweiten Beispiel tf.keras.Sequential verwendet wird, ist dies my_layer_1, my_layer_2, my_layer_3. Dies wird automatisch am Ende hinzugefügt, um Namenskonflikte zu vermeiden. Dies liegt daran, dass das erste Beispiel my_layer enthält und das zweite Beispiel nacheinander ausgeführt wird.
Ich denke, dies ist das gleiche Verhalten wie in Version 1. Zumindest die Tensorflow-Wrapper-Bibliothek dm-sonnet macht dasselbe.