Cette page a été traduite par l'API Cloud Translation.
Switch to English

Le modèle séquentiel

Voir sur TensorFlow.org Exécuter dans Google Colab Afficher la source sur GitHub Télécharger le carnet

Installer

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers

Quand utiliser un modèle séquentiel

Un modèle Sequential est approprié pour une pile simple de couches où chaque couche a exactement un tenseur d'entrée et un tenseur de sortie .

Schématiquement, le modèle Sequential suivant:

# Define Sequential model with 3 layers
model = keras.Sequential(
    [
        layers.Dense(2, activation="relu", name="layer1"),
        layers.Dense(3, activation="relu", name="layer2"),
        layers.Dense(4, name="layer3"),
    ]
)
# Call model on a test input
x = tf.ones((3, 3))
y = model(x)

équivaut à cette fonction:

# Create 3 layers
layer1 = layers.Dense(2, activation="relu", name="layer1")
layer2 = layers.Dense(3, activation="relu", name="layer2")
layer3 = layers.Dense(4, name="layer3")

# Call layers on a test input
x = tf.ones((3, 3))
y = layer3(layer2(layer1(x)))

Un modèle séquentiel n'est pas approprié lorsque:

  • Votre modèle a plusieurs entrées ou plusieurs sorties
  • Chacune de vos couches a plusieurs entrées ou plusieurs sorties
  • Vous devez faire un partage de couches
  • Vous voulez une topologie non linéaire (par exemple une connexion résiduelle, un modèle multi-branches)

Créer un modèle séquentiel

Vous pouvez créer un modèle séquentiel en passant une liste de couches au constructeur séquentiel:

model = keras.Sequential(
    [
        layers.Dense(2, activation="relu"),
        layers.Dense(3, activation="relu"),
        layers.Dense(4),
    ]
)

Ses couches sont accessibles via l'attribut layers :

model.layers
[<tensorflow.python.keras.layers.core.Dense at 0x7fcf2e879978>,
 <tensorflow.python.keras.layers.core.Dense at 0x7fcfdad262b0>,
 <tensorflow.python.keras.layers.core.Dense at 0x7fcf2c237b70>]

Vous pouvez également créer un modèle séquentiel de manière incrémentielle via la méthode add() :

model = keras.Sequential()
model.add(layers.Dense(2, activation="relu"))
model.add(layers.Dense(3, activation="relu"))
model.add(layers.Dense(4))

Notez qu'il existe également une méthode pop() correspondante pour supprimer des calques: un modèle séquentiel se comporte comme une liste de calques.

model.pop()
print(len(model.layers))  # 2
2

Notez également que le constructeur Sequential accepte un argument de name , comme n'importe quel calque ou modèle dans Keras. Ceci est utile pour annoter les graphiques TensorBoard avec des noms sémantiquement significatifs.

model = keras.Sequential(name="my_sequential")
model.add(layers.Dense(2, activation="relu", name="layer1"))
model.add(layers.Dense(3, activation="relu", name="layer2"))
model.add(layers.Dense(4, name="layer3"))

Spécification de la forme d'entrée à l'avance

En règle générale, toutes les couches de Keras doivent connaître la forme de leurs entrées afin de pouvoir créer leurs pondérations. Ainsi, lorsque vous créez un calque comme celui-ci, au départ, il n'a pas de poids:

layer = layers.Dense(3)
layer.weights  # Empty
[]

Il crée ses poids la première fois qu'il est appelé sur une entrée, car la forme des poids dépend de la forme des entrées:

# Call layer on a test input
x = tf.ones((1, 4))
y = layer(x)
layer.weights  # Now it has weights, of shape (4, 3) and (3,)
[<tf.Variable 'dense_6/kernel:0' shape=(4, 3) dtype=float32, numpy=
 array([[-0.6612724 ,  0.23639882, -0.17644602],
        [ 0.01855636, -0.7009475 , -0.05331248],
        [ 0.11539507,  0.03737205, -0.7473268 ],
        [ 0.45032406,  0.13835168, -0.1536408 ]], dtype=float32)>,
 <tf.Variable 'dense_6/bias:0' shape=(3,) dtype=float32, numpy=array([0., 0., 0.], dtype=float32)>]

Naturellement, cela s'applique également aux modèles séquentiels. Lorsque vous instanciez un modèle séquentiel sans forme d'entrée, il n'est pas "construit": il n'a pas de poids (et l'appel de model.weights entraîne une erreur indiquant simplement cela). Les pondérations sont créées lorsque le modèle voit pour la première fois des données d'entrée:

model = keras.Sequential(
    [
        layers.Dense(2, activation="relu"),
        layers.Dense(3, activation="relu"),
        layers.Dense(4),
    ]
)  # No weights at this stage!

# At this point, you can't do this:
# model.weights

# You also can't do this:
# model.summary()

# Call the model on a test input
x = tf.ones((1, 4))
y = model(x)
print("Number of weights after calling the model:", len(model.weights))  # 6
Number of weights after calling the model: 6

Une fois qu'un modèle est "construit", vous pouvez appeler sa méthode summary() pour afficher son contenu:

model.summary()
Model: "sequential_3"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_7 (Dense)              (1, 2)                    10        
_________________________________________________________________
dense_8 (Dense)              (1, 3)                    9         
_________________________________________________________________
dense_9 (Dense)              (1, 4)                    16        
=================================================================
Total params: 35
Trainable params: 35
Non-trainable params: 0
_________________________________________________________________

Cependant, il peut être très utile lors de la construction incrémentielle d'un modèle séquentiel de pouvoir afficher le résumé du modèle jusqu'à présent, y compris la forme de sortie actuelle. Dans ce cas, vous devez démarrer votre modèle en passant un objet Input à votre modèle, afin qu'il connaisse sa forme d'entrée depuis le début:

model = keras.Sequential()
model.add(keras.Input(shape=(4,)))
model.add(layers.Dense(2, activation="relu"))

model.summary()
Model: "sequential_4"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_10 (Dense)             (None, 2)                 10        
=================================================================
Total params: 10
Trainable params: 10
Non-trainable params: 0
_________________________________________________________________

Notez que l'objet Input n'est pas affiché dans le cadre de model.layers , car il ne s'agit pas d'un calque:

model.layers
[<tensorflow.python.keras.layers.core.Dense at 0x7fcf2c24aac8>]

Une alternative simple est de simplement passer un argument input_shape à votre première couche:

model = keras.Sequential()
model.add(layers.Dense(2, activation="relu", input_shape=(4,)))

model.summary()
Model: "sequential_5"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_11 (Dense)             (None, 2)                 10        
=================================================================
Total params: 10
Trainable params: 10
Non-trainable params: 0
_________________________________________________________________

Les modèles créés avec une forme d'entrée prédéfinie comme celle-ci ont toujours des pondérations (même avant de voir des données) et ont toujours une forme de sortie définie.

En général, il est recommandé de toujours spécifier à l'avance la forme d'entrée d'un modèle séquentiel si vous savez de quoi il s'agit.

Un workflow de débogage courant: add() + summary()

Lors de la création d'une nouvelle architecture séquentielle, il est utile d'empiler de manière incrémentielle les couches avec add() et d'imprimer fréquemment des résumés de modèles. Par exemple, cela vous permet de surveiller comment une pile de couches Conv2D et MaxPooling2D -échantillonne les cartes d' MaxPooling2D image:

model = keras.Sequential()
model.add(keras.Input(shape=(250, 250, 3)))  # 250x250 RGB images
model.add(layers.Conv2D(32, 5, strides=2, activation="relu"))
model.add(layers.Conv2D(32, 3, activation="relu"))
model.add(layers.MaxPooling2D(3))

# Can you guess what the current output shape is at this point? Probably not.
# Let's just print it:
model.summary()

# The answer was: (40, 40, 32), so we can keep downsampling...

model.add(layers.Conv2D(32, 3, activation="relu"))
model.add(layers.Conv2D(32, 3, activation="relu"))
model.add(layers.MaxPooling2D(3))
model.add(layers.Conv2D(32, 3, activation="relu"))
model.add(layers.Conv2D(32, 3, activation="relu"))
model.add(layers.MaxPooling2D(2))

# And now?
model.summary()

# Now that we have 4x4 feature maps, time to apply global max pooling.
model.add(layers.GlobalMaxPooling2D())

# Finally, we add a classification layer.
model.add(layers.Dense(10))
Model: "sequential_6"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d (Conv2D)              (None, 123, 123, 32)      2432      
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 121, 121, 32)      9248      
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 40, 40, 32)        0         
=================================================================
Total params: 11,680
Trainable params: 11,680
Non-trainable params: 0
_________________________________________________________________
Model: "sequential_6"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d (Conv2D)              (None, 123, 123, 32)      2432      
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 121, 121, 32)      9248      
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 40, 40, 32)        0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 38, 38, 32)        9248      
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 36, 36, 32)        9248      
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 12, 12, 32)        0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 10, 10, 32)        9248      
_________________________________________________________________
conv2d_5 (Conv2D)            (None, 8, 8, 32)          9248      
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 4, 4, 32)          0         
=================================================================
Total params: 48,672
Trainable params: 48,672
Non-trainable params: 0
_________________________________________________________________

Très pratique, non?

Que faire une fois que vous avez un modèle

Une fois que votre architecture de modèle est prête, vous voudrez:

Extraction de caractéristiques avec un modèle séquentiel

Une fois qu'un modèle séquentiel a été construit, il se comporte comme un modèle d'API fonctionnelle . Cela signifie que chaque couche a un attribut d' input et de output . Ces attributs peuvent être utilisés pour faire des choses intéressantes, comme créer rapidement un modèle qui extrait les sorties de toutes les couches intermédiaires dans un modèle séquentiel:

initial_model = keras.Sequential(
    [
        keras.Input(shape=(250, 250, 3)),
        layers.Conv2D(32, 5, strides=2, activation="relu"),
        layers.Conv2D(32, 3, activation="relu"),
        layers.Conv2D(32, 3, activation="relu"),
    ]
)
feature_extractor = keras.Model(
    inputs=initial_model.inputs,
    outputs=[layer.output for layer in initial_model.layers],
)

# Call feature extractor on test input.
x = tf.ones((1, 250, 250, 3))
features = feature_extractor(x)

Voici un exemple similaire qui extrait uniquement les entités d'une seule couche:

initial_model = keras.Sequential(
    [
        keras.Input(shape=(250, 250, 3)),
        layers.Conv2D(32, 5, strides=2, activation="relu"),
        layers.Conv2D(32, 3, activation="relu", name="my_intermediate_layer"),
        layers.Conv2D(32, 3, activation="relu"),
    ]
)
feature_extractor = keras.Model(
    inputs=initial_model.inputs,
    outputs=initial_model.get_layer(name="my_intermediate_layer").output,
)
# Call feature extractor on test input.
x = tf.ones((1, 250, 250, 3))
features = feature_extractor(x)

Transfert d'apprentissage avec un modèle séquentiel

L'apprentissage par transfert consiste à figer les couches inférieures dans un modèle et à entraîner uniquement les couches supérieures. Si vous ne le connaissez pas, assurez-vous de lire notre guide pour transférer l'apprentissage .

Voici deux plans courants d'apprentissage par transfert impliquant des modèles séquentiels.

Tout d'abord, disons que vous avez un modèle séquentiel et que vous souhaitez figer tous les calques sauf le dernier. Dans ce cas, vous model.layers simplement sur model.layers et définissez layer.trainable = False sur chaque calque, sauf le dernier. Comme ça:

model = keras.Sequential([
    keras.Input(shape=(784))
    layers.Dense(32, activation='relu'),
    layers.Dense(32, activation='relu'),
    layers.Dense(32, activation='relu'),
    layers.Dense(10),
])

# Presumably you would want to first load pre-trained weights.
model.load_weights(...)

# Freeze all layers except the last one.
for layer in model.layers[:-1]:
  layer.trainable = False

# Recompile and train (this will only update the weights of the last layer).
model.compile(...)
model.fit(...)

Un autre modèle courant consiste à utiliser un modèle séquentiel pour empiler un modèle pré-entraîné et des couches de classification fraîchement initialisées. Comme ça:

# Load a convolutional base with pre-trained weights
base_model = keras.applications.Xception(
    weights='imagenet',
    include_top=False,
    pooling='avg')

# Freeze the base model
base_model.trainable = False

# Use a Sequential model to add a trainable classifier on top
model = keras.Sequential([
    base_model,
    layers.Dense(1000),
])

# Compile & train
model.compile(...)
model.fit(...)

Si vous effectuez un transfert d'apprentissage, vous vous retrouverez probablement à utiliser fréquemment ces deux modèles.

C'est à peu près tout ce que vous devez savoir sur les modèles séquentiels!

Pour en savoir plus sur la création de modèles dans Keras, voir: