O Google I / O retorna de 18 a 20 de maio! Reserve espaço e monte sua agenda Cadastre-se agora

O modelo sequencial

Ver no TensorFlow.org Executar no Google Colab Ver fonte no GitHub Baixar caderno

Configurar

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

Quando usar um modelo sequencial

Um modelo Sequential é apropriado para uma pilha simples de camadas onde cada camada tem exatamente um tensor de entrada e um tensor de saída .

Esquematicamente, o seguinte modelo 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 esta função:

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

Um modelo sequencial não é apropriado quando:

  • Seu modelo possui múltiplas entradas ou múltiplas saídas
  • Qualquer uma de suas camadas tem múltiplas entradas ou múltiplas saídas
  • Você precisa fazer o compartilhamento de camadas
  • Você quer uma topologia não linear (por exemplo, uma conexão residual, um modelo de ramificação múltipla)

Criação de um modelo sequencial

Você pode criar um modelo sequencial passando uma lista de camadas para o construtor sequencial:

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

Suas camadas são acessíveis por meio do atributo de layers :

model.layers
[<tensorflow.python.keras.layers.core.Dense at 0x7f8af834ccc0>,
 <tensorflow.python.keras.layers.core.Dense at 0x7f8ba42a2080>,
 <tensorflow.python.keras.layers.core.Dense at 0x7f8af4506240>]

Você também pode criar um modelo sequencial de forma incremental por meio do método add() :

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

Observe que também existe um método pop() correspondente para remover camadas: um modelo Sequencial se comporta de maneira muito semelhante a uma lista de camadas.

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

Observe também que o construtor Sequential aceita um argumento de name , assim como qualquer camada ou modelo em Keras. Isso é útil para anotar gráficos do TensorBoard com nomes semanticamente 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"))

Especificando a forma de entrada com antecedência

Geralmente, todas as camadas do Keras precisam saber a forma de suas entradas para poder criar seus pesos. Então, quando você cria uma camada como esta, inicialmente, ela não tem pesos:

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

Ele cria seus pesos na primeira vez que é chamado em uma entrada, uma vez que a forma dos pesos depende da forma das 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.37242043,  0.8652495 ,  0.27929688],
        [-0.1227327 ,  0.80179167,  0.4077394 ],
        [-0.05193728,  0.6267668 , -0.00613904],
        [ 0.57773185, -0.54531974,  0.8418772 ]], dtype=float32)>,
 <tf.Variable 'dense_6/bias:0' shape=(3,) dtype=float32, numpy=array([0., 0., 0.], dtype=float32)>]

Naturalmente, isso também se aplica aos modelos sequenciais. Quando você instancia um modelo Sequencial sem uma forma de entrada, ele não é "construído": ele não tem pesos (e chamar model.weights resulta em um erro informando apenas isso). Os pesos são criados quando o modelo vê pela primeira vez alguns dados 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

Depois que um modelo é "construído", você pode chamar seu método summary() para exibir seu conteúdo:

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
_________________________________________________________________

No entanto, pode ser muito útil ao construir um modelo Sequencial de forma incremental para poder exibir o resumo do modelo até o momento, incluindo a forma de saída atual. Nesse caso, você deve iniciar seu modelo passando um objeto de Input para seu modelo, para que ele conheça sua forma de entrada desde o início:

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
_________________________________________________________________

Observe que o objeto Input não é exibido como parte de model.layers , pois não é uma camada:

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

Uma alternativa simples é apenas passar um argumento input_shape para sua primeira camada:

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
_________________________________________________________________

Modelos construídos com uma forma de entrada predefinida como esta sempre têm pesos (mesmo antes de ver qualquer dado) e sempre têm uma forma de saída definida.

Em geral, é uma prática recomendada sempre especificar a forma de entrada de um modelo Sequencial com antecedência, se você souber o que é.

Um fluxo de trabalho de depuração comum: add() + summary()

Ao construir uma nova arquitetura Sequencial, é útil empilhar camadas incrementalmente com add() e imprimir resumos de modelos com frequência. Por exemplo, isto permite-lhe controlar a forma como uma pilha de Conv2D e MaxPooling2D camadas é downsampling mapas de características imagem:

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
_________________________________________________________________

Muito prático, certo?

O que fazer quando você tiver um modelo

Assim que a arquitetura do seu modelo estiver pronta, você desejará:

Extração de recursos com um modelo sequencial

Depois que um modelo Sequencial é construído, ele se comporta como um modelo de API Funcional . Isso significa que cada camada possui um atributo de input e output . Esses atributos podem ser usados ​​para fazer coisas legais, como criar rapidamente um modelo que extraia as saídas de todas as camadas intermediárias em um modelo Sequencial:

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)

Aqui está um exemplo semelhante que extrai apenas recursos de uma camada:

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)

Transfira a aprendizagem com um modelo sequencial

A aprendizagem por transferência consiste em congelar as camadas inferiores de um modelo e apenas treinar as camadas superiores. Se você não estiver familiarizado com ele, certifique-se de ler nosso guia para transferir aprendizagem .

Aqui estão dois planos de aprendizagem de transferência comuns envolvendo modelos sequenciais.

Primeiro, digamos que você tenha um modelo Sequencial e queira congelar todas as camadas, exceto a última. Nesse caso, você simplesmente model.layers sobre model.layers e layer.trainable = False em cada camada, exceto a última. Como isso:

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

Outro projeto comum é usar um modelo Sequencial para empilhar um modelo pré-treinado e algumas camadas de classificação recém-inicializadas. Como isso:

# 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 você transferir o aprendizado, provavelmente usará frequentemente esses dois padrões.

Isso é tudo que você precisa saber sobre modelos sequenciais!

Para saber mais sobre a construção de modelos em Keras, consulte: