Écriture de couche personnalisée tf.keras recommandée et comportement de nom de variable

introduction

J'ai trouvé un comportement qui n'est pas documenté sur le comportement des noms dans les couches personnalisées de tf.keras, alors faites-le moi savoir. Le "nom de la variable" mentionné ici n'est pas le nom de la variable dans la syntaxe Python, mais le nom (obligatoire comme argument) donné à la variable Tensorflow (tf.Variable).

Avant l'écriture recommandée, je vais vous expliquer un peu les noms de variables.

Exemple spécifique de nom de variable

Ce n'est pas my.v1 ou self.v2 dans l'exemple de code ci-dessous, mais my_variable1 ou my_variable2.

import tensorflow as tf

#Exemple de code de calque personnalisé
#Couche entièrement connectée auto-fabriquée
class MyLayer(tf.keras.layers.Layer):
    def __init__(self, output_dim):
        super().__init__()
        self.output_dim = output_dim

        #Terme de biais
        #Cela ne dépend pas de la taille des données d'entrée
        self.v1 = self.add_weight(name='my_variable1', shape=[output_dim])

    def build(self, input_shape):
        #matrice affine
        #Dépend de la taille des données d'entrée
        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

Le contenu ici est le contenu du tutoriel officiel.

Y a-t-il quelque chose qui ne va pas?

Courir pour le moment

Exécutons-le et vérifions-le.

model = MyLayer(output_dim=3)
#La méthode de construction est exécutée la première fois que vous entrez des données, entrez donc les données appropriées
x = tf.random.normal(shape=(3, 5))
y = model(x)

print(model.trainable_variables)
↓ C'est le nom
[<tf.Variable 'my_variable1:0' shape=(3,) dtype=float32, numpy=array([-0.56484747,  0.00200152,  0.42238712], dtype=float32)>, 
↓ C'est le nom
<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 et my_layer / my_variable2: 0. Il y a quelque chose en plus, mais j'ai confirmé que les noms des variables sont respectivement my_variable1 et my_variable2, donc c'est OK.

Est ce juste?

Lorsque les couches sont empilées

Continuons avec l'exemple précédent.

#Lorsque vous empilez vos propres couches
model = tf.keras.Sequential([
    MyLayer(3),
    MyLayer(3),
    MyLayer(3)
])

[<tf.Variable 'my_variable1:0' shape=(3,) dtype=float32, (Abréviation)>,
 <tf.Variable 'sequential/my_layer_1/my_variable2:0' shape=(5, 3) dtype=float32, (Abréviation))>,
 <tf.Variable 'my_variable1:0' shape=(3,) dtype=float32, (Abréviation)>,
 <tf.Variable 'sequential/my_layer_2/my_variable2:0' shape=(3, 3) dtype=float32, (Abréviation)>,
 <tf.Variable 'my_variable1:0' shape=(3,) dtype=float32, (Abréviation)>,
 <tf.Variable 'sequential/my_layer_3/my_variable2:0' shape=(3, 3) dtype=float32, (Abréviation)]

ma_variable1 est pleine (pleure). Indiscernable.

Quand j'ai dessiné un histogramme de variables sur Tensorboard, les noms se sont affrontés et je ne pouvais pas comprendre la raison.

Comment écrire un calque personnalisé recommandé

class MyLayer(tf.keras.layers.Layer):
    def __init__(self, output_dim):
        super().__init__()
        self.output_dim = output_dim
       
    def build(self, input_shape):
        #Terme de biais
        #Cela ne dépend pas de la taille des données d'entrée
        self.v1 = self.add_weight(name='my_variable1', shape=[output_dim])

        #matrice affine
        #Dépend de la taille des données d'entrée
        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

Déclarez simplement toutes les variables de la méthode de construction.

Étant donné que Tensorflow est également défini par exécution après la version 2, je pense qu'il ne peut pas être résolu tant que le modèle et l'ordre des couches ne sont pas exécutés en premier. Pour cette raison, je pense qu'il y a une grande différence entre la méthode \ _ \ _ init__ et la méthode biuld.

À propos, tf.keras.layers.Dense etc. sont tous déclarés dans la méthode de construction, vous pouvez donc l'utiliser en toute confiance.

Résumé

Lorsque vous déclarez une variable dans une couche personnalisée, assurez-vous de la déclarer dans la méthode de construction. Ne déclarez pas dans la méthode \ _ \ _ init__.

De côté

Explication du comportement du traitement des noms

Qu'est-ce que 0 à la fin?

Il sera ajouté automatiquement selon les spécifications de Tensorflow. Lors de l'exécution sur un multi-GPU, une copie de la variable est faite pour chaque GPU, donc chacun est numéroté 0, 1, 2, ... dans cet ordre. Les spécifications ici sont les mêmes que dans la version 1.

Dans la version 2, vous pouvez vérifier en faisant la même chose que ci-dessus avec plusieurs GPU en utilisant tf.distribute.MirroredStrategy etc.

Quel est le premier my_layer?

my_layer est le nom par défaut si vous n'avez pas explicitement nommé MyLayer. Le nom de la classe est automatiquement converti en cas de serpent.

De plus, lorsque tf.keras.Sequential est utilisé dans le deuxième exemple, il s'agit de my_layer_1, my_layer_2, my_layer_3. Ceci est automatiquement ajouté à la fin pour éviter les conflits de noms. En effet, le premier exemple a my_layer et le deuxième exemple est exécuté successivement.

Je pense que c'est le même comportement que dans la version 1. Au moins la bibliothèque de wrapper dm-sonnet de Tensorflow fait de même.

Recommended Posts

Écriture de couche personnalisée tf.keras recommandée et comportement de nom de variable
Décorateur qui vérifie les noms de variables et modifie le comportement
Précautions lors de l'utilisation de tf.keras.layers.TimeDistributed pour la couche personnalisée tf.keras