¡El Día de la Comunidad de ML es el 9 de noviembre! Únase a nosotros para recibir actualizaciones de TensorFlow, JAX, y más Más información

El modelo secuencial

Ver en TensorFlow.org Ejecutar en Google Colab Ver fuente en GitHub Descargar cuaderno

Configuración

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

Cuándo usar un modelo secuencial

A Sequential modelo es apropiado para una pila llanura de capas, donde cada capa tiene exactamente un tensor de entrada y un tensor de salida.

Esquemáticamente, la siguiente Sequential modelo:

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

es equivalente a esta función:

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

El modelo A secuencial no es apropiado cuando:

  • Su modelo tiene múltiples entradas o múltiples salidas
  • Cualquiera de sus capas tiene múltiples entradas o múltiples salidas
  • Necesitas compartir capas
  • Quiere una topología no lineal (por ejemplo, una conexión residual, un modelo de varias ramas)

Creando un modelo secuencial

Puede crear un modelo secuencial pasando una lista de capas al constructor secuencial:

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

Sus capas son accesibles a través de layers de atributos:

model.layers
[<keras.layers.core.Dense at 0x7fdc784478d0>,
 <keras.layers.core.Dense at 0x7fdbbc3c4650>,
 <keras.layers.core.Dense at 0x7fdbbc3c4a10>]

También puede crear un modelo secuencial de forma incremental a través de la add() método:

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

Tenga en cuenta que también hay una correspondiente pop() método para eliminar las capas: un modelo secuencial se comporta muy parecido a una lista de capas.

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

También tenga en cuenta que el constructor secuencial acepta un name argumento, al igual que cualquier capa o modelo en el Keras. Esto es útil para anotar gráficos de TensorBoard con nombres semánticamente significativos.

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

Especificar la forma de entrada de antemano

Generalmente, todas las capas de Keras necesitan conocer la forma de sus entradas para poder crear sus pesos. Entonces, cuando crea una capa como esta, inicialmente, no tiene pesos:

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

Crea sus pesos la primera vez que se llama en una entrada, ya que la forma de los pesos depende de la forma de las entradas:

# 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.5319189 , -0.8767905 , -0.63919735],
        [-0.6276014 ,  0.1689707 , -0.57695866],
        [ 0.6710613 ,  0.5354214 , -0.00893992],
        [ 0.15670097, -0.15280598,  0.8865864 ]], dtype=float32)>,
 <tf.Variable 'dense_6/bias:0' shape=(3,) dtype=float32, numpy=array([0., 0., 0.], dtype=float32)>]

Naturalmente, esto también se aplica a los modelos secuenciales. Cuando se instancia un modelo secuencial sin una forma de entrada, no se "construye": no tiene pesos (y llamando model.weights resultados en un error que indica simplemente esto). Los pesos se crean cuando el modelo ve por primera vez algunos datos de entrada:

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 vez que un modelo se "construye", puede llamar a su summary() método para mostrar su contenido:

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
_________________________________________________________________

Sin embargo, puede ser muy útil cuando se crea un modelo secuencial de forma incremental para poder mostrar el resumen del modelo hasta el momento, incluida la forma de salida actual. En este caso, usted debe comenzar su modelo mediante el paso de una Input objeto a su modelo, para que conozca su forma de entrada desde el principio:

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
_________________________________________________________________

Tenga en cuenta que la Input de objetos no se muestra como parte de model.layers , ya que no es una capa:

model.layers
[<keras.layers.core.Dense at 0x7fdbbc37c390>]

Una alternativa más sencilla es simplemente pasar un input_shape argumento para su primera capa:

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
_________________________________________________________________

Los modelos construidos con una forma de entrada predefinida como esta siempre tienen pesos (incluso antes de ver cualquier dato) y siempre tienen una forma de salida definida.

En general, es una práctica recomendada especificar siempre la forma de entrada de un modelo secuencial de antemano si sabe cuál es.

Un flujo de trabajo de depuración comunes: add() + summary()

Cuando la construcción de una nueva arquitectura secuencial, es útil para apilar capas de forma incremental con add() y con frecuencia imprimir resúmenes modelo. Por ejemplo, esto le permite controlar cómo una pila de Conv2D y MaxPooling2D capas se Downsampling mapas de características de imagen:

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
_________________________________________________________________

Muy práctico, ¿verdad?

Qué hacer una vez que tenga un modelo

Una vez que la arquitectura de su modelo esté lista, querrá:

Extracción de características con un modelo secuencial

Una vez que un modelo secuencial se ha construido, se comporta como un modelo funcional de la API . Esto significa que cada capa tiene una input y output de atributos. Estos atributos se pueden usar para hacer cosas interesantes, como crear rápidamente un modelo que extrae los resultados de todas las capas intermedias en un modelo secuencial:

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)

Aquí hay un ejemplo similar que solo extrae características de una capa:

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)

Transferir el aprendizaje con un modelo secuencial

El aprendizaje por transferencia consiste en congelar las capas inferiores en un modelo y solo entrenar las capas superiores. Si no está familiarizado con él, asegúrese de leer nuestra guía para el aprendizaje de transferencia .

Aquí hay dos planos comunes de aprendizaje por transferencia que involucran modelos secuenciales.

Primero, digamos que tiene un modelo secuencial y desea congelar todas las capas excepto la última. En este caso, sólo tendría que iterar sobre model.layers y conjunto layer.trainable = False en cada capa, excepto la última. Como esto:

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

Otro plan común es utilizar un modelo secuencial para apilar un modelo previamente entrenado y algunas capas de clasificación recién inicializadas. Como esto:

# 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 transfiere el aprendizaje, probablemente se encontrará utilizando con frecuencia estos dos patrones.

¡Eso es todo lo que necesita saber sobre los modelos secuenciales!

Para obtener más información sobre la construcción de modelos en Keras, consulte: