[PYTHON] Détournement de couches de modèle de keras entraînées

introduction

Cet article est un mémo pour ma propre étude. Si vous avez des questions, je vous serais reconnaissant de bien vouloir les signaler.

Cet apprentissage est le suivant: Est-il possible de prendre une couche d'un modèle créé et formé avec des keras et de la réutiliser pour un modèle nouvellement créé?

Modèle formé

Utilisez le modèle de cette page (https://qiita.com/yoho/items/e9a65b10ca510ab50a36). Le nom de la variable est model.

001.py


model.summary()

#Layer (type)                 Output Shape              Param #   
#=================================================================
#dense_1 (Dense)              (None, 100)               1100      
#_________________________________________________________________
#dense_2 (Dense)              (None, 100)               10100     
#_________________________________________________________________
#dense_3 (Dense)              (None, 40)                4040      
#_________________________________________________________________
#dense_4 (Dense)              (None, 20)                820       
#_________________________________________________________________
#dense_5 (Dense)              (None, 2)                 42        
#=================================================================
#Total params: 16,102
#Trainable params: 16,102
#Non-trainable params: 0
_________________________________________________________________

Utilisez vars () pour découvrir les variables du modèle.

002.py


vars(model)

Bien que cela ne soit pas illustré ici, vous pouvez voir les variables du modèle. Parmi eux, la variable _layers semble contenir une liste d'objets de calque.

J'essaierai d'y accéder.

003.py


model._layers
#La sortie est séparée par des sauts de ligne pour une visualisation facile.
#[<keras.engine.input_layer.InputLayer object at 0x138144208>, 
#<keras.layers.core.Dense object at 0x13811af98>, 
#<keras.layers.core.Dense object at 0x138144320>, 
#<keras.layers.core.Dense object at 0x1381443c8>, 
#<keras.layers.core.Dense object at 0x138144518>, 
#<keras.layers.core.Dense object at 0x1381741d0>]

Vous pouvez également y accéder en tant que model.layers. La méthode getter est-elle définie? Dans ce cas, il semble qu'il n'y ait pas de input_Layer au début par rapport au cas de model._layers.

004.py


model.layers
#La sortie est séparée par des sauts de ligne pour une visualisation facile.
#[<keras.layers.core.Dense object at 0x13811af98>, 
#<keras.layers.core.Dense object at 0x138144320>, 
#<keras.layers.core.Dense object at 0x1381443c8>, 
#<keras.layers.core.Dense object at 0x138144518>, 
#keras.layers.core.Dense object at 0x1381741d0>]

Examinez la dernière couche

Qu'en est-il de la dernière couche avec le moins de paramètres? Utilisez pprint pour la lisibilité.

005.py



import pprint
pprint.pprint(vars(model.layers[4]))
#Ce qui suit est la sortie.
"""
{'_built': True,
 '_inbound_nodes': [<keras.engine.base_layer.Node object at 0x138174e10>],
 '_initial_weights': None,
 '_losses': [],
 '_metrics': [],
 '_non_trainable_weights': [],
 '_outbound_nodes': [],
 '_per_input_losses': {},
 '_per_input_updates': {},
 '_trainable_weights': [<tf.Variable 'dense_5/kernel:0' shape=(20, 2) dtype=float32, numpy=
array([[-0.07533632,  0.20118327],
       [-0.17458896, -0.44313124],
       [ 0.4008763 ,  0.3295961 ],
       [-0.40597808, -0.02159814],
       [ 0.59269255, -0.15129048],
       [-0.14078082, -0.44002545],
       [ 0.18300773,  0.17778364],
       [ 0.3685053 , -0.36274177],
       [-0.28516215, -0.0659026 ],
       [ 0.45126018, -0.2892398 ],
       [ 0.19851999, -0.39362603],
       [ 0.2631754 ,  0.40239784],
       [ 0.08184562, -0.08194606],
       [-0.43493706,  0.18896711],
       [ 0.36158973,  0.20016526],
       [-0.05036243, -0.20633343],
       [-0.41589907,  0.57210416],
       [-0.10199612, -0.37373352],
       [ 0.30416492, -0.19923651],
       [ 0.02667725, -0.5090254 ]], dtype=float32)>,
                        <tf.Variable 'dense_5/bias:0' shape=(2,) dtype=float32, numpy=array([0.05854932, 0.07379959], dtype=float32)>],
 '_updates': [],
 'activation': <function linear at 0x1380400d0>,
 'activity_regularizer': None,
 'bias': <tf.Variable 'dense_5/bias:0' shape=(2,) dtype=float32, numpy=array([0.05854932, 0.07379959], dtype=float32)>,
 'bias_constraint': None,
 'bias_initializer': <keras.initializers.Zeros object at 0x138180400>,
 'bias_regularizer': None,
 'dtype': 'float32',
 'input_spec': InputSpec(min_ndim=2, axes={-1: 20}),
 'kernel': <tf.Variable 'dense_5/kernel:0' shape=(20, 2) dtype=float32, numpy=
array([[-0.07533632,  0.20118327],
       [-0.17458896, -0.44313124],
       [ 0.4008763 ,  0.3295961 ],
       [-0.40597808, -0.02159814],
       [ 0.59269255, -0.15129048],
       [-0.14078082, -0.44002545],
       [ 0.18300773,  0.17778364],
       [ 0.3685053 , -0.36274177],
       [-0.28516215, -0.0659026 ],
       [ 0.45126018, -0.2892398 ],
       [ 0.19851999, -0.39362603],
       [ 0.2631754 ,  0.40239784],
       [ 0.08184562, -0.08194606],
       [-0.43493706,  0.18896711],
       [ 0.36158973,  0.20016526],
       [-0.05036243, -0.20633343],
       [-0.41589907,  0.57210416],
       [-0.10199612, -0.37373352],
       [ 0.30416492, -0.19923651],
       [ 0.02667725, -0.5090254 ]], dtype=float32)>,
 'kernel_constraint': None,
 'kernel_initializer': <keras.initializers.VarianceScaling object at 0x138174b70>,
 'kernel_regularizer': None,
 'name': 'dense_5',
 'stateful': False,
 'supports_masking': True,
 'trainable': True,                  #######Important ici#######
 'units': 2,
 'use_bias': True}
"""

La dernière couche reçoit 20 sorties de la couche précédente et produit 2 sorties, donc le nombre de paramètres de poids est de 20 x 2 = 40 et les paramètres de polarisation sont de 2.

Je ne suis pas sûr, mais il semble avoir deux des mêmes paramètres de poids (_trainable_weights [0] et kernel).

Quel est le paramètre de poids réel? Vérifions _trainable_weights [0] avec type ().

006.py


type( model.layers[4]._trainable_weights[0] )
#<class 'tensorflow.python.ops.resource_variable_ops.ResourceVariable'>

Cela ressemble à un objet ResourceVariable dans tensorflow, mais je ne vais pas chercher plus loin ici.

Il semble que get_weights () puisse être utilisé pour récupérer une liste de poids et de biais. La liste comporte 2 éléments.

007.py


type(model.layers[4].get_weights())
#<class 'list'>
len(model.layers[4].get_weights())
#2

Le contenu de cette liste est ndarray. Je vais regarder le contenu.

008.py


type(model.layers[4].get_weights()[0])#0ème confirmation dans la liste
#<class 'numpy.ndarray'>
model.layers[4].get_weights()[0]#0e dans la liste
"""
array([[-0.07533632,  0.20118327],
       [-0.17458896, -0.44313124],
       [ 0.4008763 ,  0.3295961 ],
       [-0.40597808, -0.02159814],
       [ 0.59269255, -0.15129048],
       [-0.14078082, -0.44002545],
       [ 0.18300773,  0.17778364],
       [ 0.3685053 , -0.36274177],
       [-0.28516215, -0.0659026 ],
       [ 0.45126018, -0.2892398 ],
       [ 0.19851999, -0.39362603],
       [ 0.2631754 ,  0.40239784],
       [ 0.08184562, -0.08194606],
       [-0.43493706,  0.18896711],
       [ 0.36158973,  0.20016526],
       [-0.05036243, -0.20633343],
       [-0.41589907,  0.57210416],
       [-0.10199612, -0.37373352],
       [ 0.30416492, -0.19923651],
       [ 0.02667725, -0.5090254 ]], dtype=float32)
"""

type(model.layers[4].get_weights()[1])#Première confirmation sur la liste
#<class 'numpy.ndarray'>
model.layers[4].get_weights()[1]#Premier dans la liste
#array([0.05854932, 0.07379959], dtype=float32)

Retirez la couche et essayez de créer un nouveau modèle.

Je ne sais pas quand les paramètres seront initialisés lorsque je construis le modèle, je vais donc vérifier s'ils sont initialisés lorsque je les incorpore dans le modèle.

Ici, nous utiliserons la dernière couche des cinq couches du modèle comme deuxième couche du nouveau modèle.

Puisque la couche de diversion est une couche qui reçoit 20 entrées, la couche d'entrée du nouveau modèle doit accepter 20 entrées.

009.py


inputs = keras.layers.Input(shape=(20,))
x = model.layers[4](inputs)
model_new = keras.Model(inputs=inputs, outputs=x)

J'étais connecté.

Si le calque est le même que le 5ème calque du modèle précédent, Vérifiez si les paramètres ont changé.

010.py


model_new.layers[1]
<keras.layers.core.Dense object at 0x1381741d0>#L'adresse de l'objet est la même.
model_new.layers[1].get_weights()[0]#Vérifiez si les paramètres ont changé-->Inchangé.
"""
array([[-0.07533632,  0.20118327],
       [-0.17458896, -0.44313124],
       [ 0.4008763 ,  0.3295961 ],
       [-0.40597808, -0.02159814],
       [ 0.59269255, -0.15129048],
       [-0.14078082, -0.44002545],
       [ 0.18300773,  0.17778364],
       [ 0.3685053 , -0.36274177],
       [-0.28516215, -0.0659026 ],
       [ 0.45126018, -0.2892398 ],
       [ 0.19851999, -0.39362603],
       [ 0.2631754 ,  0.40239784],
       [ 0.08184562, -0.08194606],
       [-0.43493706,  0.18896711],
       [ 0.36158973,  0.20016526],
       [-0.05036243, -0.20633343],
       [-0.41589907,  0.57210416],
       [-0.10199612, -0.37373352],
       [ 0.30416492, -0.19923651],
       [ 0.02667725, -0.5090254 ]], dtype=float32)
"""

Quand j'ai examiné cette couche avec vars (), Seule la valeur de la liste avec \ _inbound_nodes comme clé était différente.

011.py


pprint.pprint(model.layers[1]._inbound_nodes)
#[<keras.engine.base_layer.Node object at 0x138144be0>]
pprint.pprint(model_new.layers[1]._inbound_nodes)
#[<keras.engine.base_layer.Node object at 0x138174e10>,
# <keras.engine.base_layer.Node object at 0x110cfe198>]#Cela augmente.

keras.engine.base_layer.Node est un peu en attente.

Pour que les paramètres de ce calque ne changent pas pendant l'entraînement (geler le calque) Définissez la propriété entraînable sur False.

012.py


model_new.layers[1].trainable=False

Le modèle doit être compilé.

Résumé

  1. Vous pouvez extraire votre couche préférée du modèle keras NN entraîné et l'utiliser pour d'autres modèles.
  2. Vous pouvez figer les paramètres de calque afin qu'ils ne changent pas.

Recommended Posts

Détournement de couches de modèle de keras entraînées
Implémentation de VGG16 à l'aide de Keras créé sans utiliser de modèle entraîné
Publication d'un modèle entraîné de fastText
Résumé de Tensorflow / Keras
Visualisation bidimensionnelle des vecteurs de documents à l'aide du modèle entraîné Word2Vec
Visualiser le modèle Keras avec Python 3.5
Avantages d'affiner le modèle de Django
[Keras] inférence par lots d'arcface
Défi la classification des images par TensorFlow2 + Keras 4 ~ Prédisons avec un modèle entraîné ~