Сохраните дату! Google I / O возвращается 18-20 мая Зарегистрируйтесь сейчас
Эта страница переведена с помощью Cloud Translation API.
Switch to English

Последовательная модель

Посмотреть на TensorFlow.org Запускаем в Google Colab Посмотреть исходный код на GitHub Скачать блокнот

Настраивать

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

Когда использовать последовательную модель

Sequential модель подходит для простого стека слоев, где каждый слой имеет ровно один входной тензор и один выходной тензор .

Схематично следующая 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)

эквивалентно этой функции:

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

Последовательная модель не подходит, когда:

  • Ваша модель имеет несколько входов или несколько выходов
  • Любой из ваших слоев имеет несколько входов или несколько выходов.
  • Вам нужно сделать общий доступ к слоям
  • Вам нужна нелинейная топология (например, остаточное соединение, модель с несколькими ветвями)

Создание последовательной модели

Вы можете создать модель Sequential, передав список слоев в конструктор Sequential:

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

Его слои доступны через атрибут 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>]

Вы также можете создать последовательную модель постепенно с помощью метода add() :

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

Обратите внимание, что существует также соответствующий метод pop() для удаления слоев: последовательная модель ведет себя очень похоже на список слоев.

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

Также обратите внимание, что конструктор Sequential принимает аргумент name , как и любой слой или модель в Keras. Это полезно для аннотирования графов TensorBoard семантически значимыми именами.

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

Предварительное указание формы ввода

Как правило, все слои в Keras должны знать форму своих входов, чтобы иметь возможность создавать свои веса. Итак, когда вы создаете такой слой, изначально у него нет весов:

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

Он создает свои веса при первом вызове на входе, поскольку форма весов зависит от формы входов:

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

Естественно, это относится и к последовательным моделям. Когда вы создаете экземпляр последовательной модели без входной формы, она не «строится»: у нее нет весов (и вызов model.weights приводит к ошибке, model.weights только на это). Веса создаются, когда модель впервые видит некоторые входные данные:

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

Когда модель «построена», вы можете вызвать ее метод summary() для отображения ее содержимого:

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
_________________________________________________________________

Однако это может быть очень полезно при пошаговом построении последовательной модели, чтобы иметь возможность отображать сводку модели на данный момент, включая текущую форму вывода. В этом случае вы должны начать свою модель, передав ей объект Input , чтобы она с самого начала знала свою форму ввода:

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
_________________________________________________________________

Обратите внимание, что объект Input не отображается как часть model.layers , поскольку он не является слоем:

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

Простая альтернатива - просто передать аргумент input_shape вашему первому слою:

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
_________________________________________________________________

Модели, построенные с использованием предопределенной формы ввода, подобной этой, всегда имеют веса (даже до того, как отображаются какие-либо данные) и всегда имеют определенную форму вывода.

В общем, рекомендуется всегда заранее указывать входную форму последовательной модели, если вы знаете, что это такое.

Обычный рабочий процесс отладки: add() + summary()

При построении новой последовательной архитектуры полезно постепенно складывать слои с помощью add() и часто распечатывать сводки моделей. Например, это позволяет вам отслеживать, как стек Conv2D и MaxPooling2D дискретизацию карт функций изображения:

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
_________________________________________________________________

Очень практично, правда?

Что делать, если у вас есть модель

Когда ваша модельная архитектура будет готова, вы захотите:

Извлечение признаков с помощью последовательной модели

После построения последовательной модели она ведет себя как модель функционального API . Это означает, что каждый слой имеет атрибут input и output . Эти атрибуты можно использовать для изящных вещей, таких как быстрое создание модели, которая извлекает выходные данные всех промежуточных слоев в последовательной модели:

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)

Вот аналогичный пример, который извлекает объекты только из одного слоя:

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)

Перенос обучения с последовательной моделью

Трансферное обучение состоит из замораживания нижних слоев модели и обучения только верхних слоев. Если вы не знакомы с ним, обязательно прочтите наше руководство по трансферному обучению .

Вот две распространенные схемы трансферного обучения с использованием последовательных моделей.

Во-первых, предположим, что у вас есть последовательная модель, и вы хотите заморозить все слои, кроме последнего. В этом случае вы просто перебираете model.layers и устанавливаете layer.trainable = False для каждого слоя, кроме последнего. Так:

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

Другой распространенный план - использование последовательной модели для объединения предварительно обученной модели и некоторых недавно инициализированных слоев классификации. Так:

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

Если вы используете переносное обучение, вы, вероятно, будете часто использовать эти два паттерна.

Это все, что вам нужно знать о последовательных моделях!

Чтобы узнать больше о построении моделей в Керасе, см .: