Questa pagina è stata tradotta dall'API Cloud Translation.
Switch to English

Il modello sequenziale

Visualizza su TensorFlow.org Esegui in Google Colab Visualizza sorgente su GitHub Scarica notebook

Impostare

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

Quando utilizzare un modello sequenziale

Un modello Sequential è appropriato per una semplice pila di livelli in cui ogni livello ha esattamente un tensore di input e un tensore di output .

Schematicamente, il seguente modello Sequential :

# 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)

è equivalente a questa funzione:

# 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 modello sequenziale non è appropriato quando:

  • Il tuo modello ha più ingressi o più uscite
  • Ciascuno dei tuoi livelli ha più ingressi o più uscite
  • Devi fare la condivisione dei livelli
  • Si desidera una topologia non lineare (ad es. Una connessione residua, un modello multi-ramo)

Creazione di un modello sequenziale

È possibile creare un modello sequenziale passando un elenco di livelli al costruttore sequenziale:

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

I suoi livelli sono accessibili tramite l'attributo layers :

model.layers
[<tensorflow.python.keras.layers.core.Dense at 0x7f37ffe66668>,
 <tensorflow.python.keras.layers.core.Dense at 0x7f37f553fc50>,
 <tensorflow.python.keras.layers.core.Dense at 0x7f37680de2b0>]

Puoi anche creare un modello sequenziale in modo incrementale tramite il metodo add() :

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

Si noti che esiste anche un metodo pop() corrispondente per rimuovere i livelli: un modello sequenziale si comporta in modo molto simile a un elenco di livelli.

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

Si noti inoltre che il costruttore sequenziale accetta un argomento name , proprio come qualsiasi livello o modello in Keras. Questo è utile per annotare i grafici TensorBoard con nomi semanticamente significativi.

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"))

Specificare in anticipo la forma di input

In generale, tutti i livelli in Keras devono conoscere la forma dei loro input per poter creare i loro pesi. Quindi quando crei un livello come questo, inizialmente, non ha pesi:

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

Crea i suoi pesi la prima volta che viene chiamato su un input, poiché la forma dei pesi dipende dalla forma degli input:

# 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.8131663 , -0.49988765, -0.02397203],
        [-0.3190418 ,  0.01101786,  0.85226357],
        [-0.602435  , -0.10381919,  0.63280225],
        [-0.3388477 ,  0.11859643, -0.10677373]], dtype=float32)>,
 <tf.Variable 'dense_6/bias:0' shape=(3,) dtype=float32, numpy=array([0., 0., 0.], dtype=float32)>]

Naturalmente, questo vale anche per i modelli sequenziali. Quando si istanzia un modello sequenziale senza una forma di input, non è "costruito": non ha pesi (e la chiamata a model.weights un errore che indica proprio questo). I pesi vengono creati quando il modello vede per la prima volta alcuni dati di input:

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

Una volta che un modello è "costruito", puoi chiamare il suo metodo summary() per visualizzarne il contenuto:

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

Tuttavia, può essere molto utile quando si costruisce un modello sequenziale in modo incrementale per poter visualizzare il riepilogo del modello fino a quel momento, inclusa la forma di output corrente. In questo caso, dovresti avviare il tuo modello passando un oggetto Input al tuo modello, in modo che conosca la sua forma di input dall'inizio:

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
_________________________________________________________________

Tieni presente che l'oggetto Input non viene visualizzato come parte di model.layers , poiché non è un livello:

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

Una semplice alternativa è semplicemente passare un argomento input_shape al tuo primo livello:

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
_________________________________________________________________

I modelli costruiti con una forma di input predefinita come questa hanno sempre dei pesi (anche prima di vedere i dati) e hanno sempre una forma di output definita.

In generale, è consigliabile specificare sempre la forma di input di un modello sequenziale in anticipo se si sa di cosa si tratta.

Un flusso di lavoro di debug comune: add() + summary()

Quando si crea una nuova architettura sequenziale, è utile impilare in modo incrementale i livelli con add() e stampare frequentemente i riepiloghi del modello. Ad esempio, questo consente di monitorare in che modo uno stack di Conv2D e MaxPooling2D downsampling delle mappe delle caratteristiche dell'immagine:

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
_________________________________________________________________

Molto pratico, vero?

Cosa fare una volta che hai un modello

Una volta che l'architettura del tuo modello è pronta, vorrai:

Estrazione delle caratteristiche con un modello sequenziale

Una volta che un modello sequenziale è stato costruito, si comporta come un modello API funzionale . Ciò significa che ogni livello ha un attributo di input e output . Questi attributi possono essere usati per fare cose chiare, come creare rapidamente un modello che estrae gli output di tutti i livelli intermedi in un modello sequenziale:

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)

Ecco un esempio simile che estrae solo elementi da un livello:

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)

Trasferisci l'apprendimento con un modello sequenziale

L'apprendimento del trasferimento consiste nel congelare gli strati inferiori in un modello e addestrare solo gli strati superiori. Se non lo conosci, assicurati di leggere la nostra guida per trasferire l'apprendimento .

Qui ci sono due progetti comuni di apprendimento del trasferimento che coinvolgono modelli sequenziali.

Innanzitutto, supponiamo di avere un modello sequenziale e di voler congelare tutti i livelli tranne l'ultimo. In questo caso, devi semplicemente iterare su model.layers e impostare layer.trainable = False su ogni livello, tranne l'ultimo. Come questo:

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 altro progetto comune consiste nell'utilizzare un modello sequenziale per impilare un modello pre-addestrato e alcuni livelli di classificazione appena inizializzati. Come questo:

# 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(...)

Se trasferisci l'apprendimento, probabilmente ti ritroverai a usare spesso questi due modelli.

Questo è tutto ciò che devi sapere sui modelli sequenziali!

Per saperne di più sulla costruzione di modelli in Keras, vedere: