[PYTHON] Empfohlenes benutzerdefiniertes Layer-Schreiben von tf.keras und Verhalten bei Variablennamen

Einführung

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.

Spezifisches Beispiel für den Variablennamen

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.

Stimmt irgendetwas nicht?

Lauf vorerst

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?

Wenn Schichten gestapelt werden

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.

So schreiben Sie eine empfohlene benutzerdefinierte Ebene

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.

Zusammenfassung

Wenn Sie eine Variable in einer benutzerdefinierten Ebene deklarieren, müssen Sie sie in der Erstellungsmethode deklarieren. Deklarieren Sie nicht in der Methode \ _ \ _ init__.

Beiseite

Erläuterung des Verhaltens der Namensverarbeitung

Was ist 0 am Ende?

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.

Was ist der erste my_layer?

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.

Recommended Posts

Empfohlenes benutzerdefiniertes Layer-Schreiben von tf.keras und Verhalten bei Variablennamen
Dekorateur, der Variablennamen überprüft und das Verhalten ändert
Vorsichtsmaßnahmen bei der Verwendung von tf.keras.layers.TimeDistributed für die benutzerdefinierte Ebene von tf.keras