Keras深度学习框架第二讲:Sequential模型

80 篇文章 0 订阅
50 篇文章 4 订阅

1、Sequential模型简介

Sequential模型是一种非常基础且常用的模型结构。它实际上是一种线性的、顺序的模型,由一系列层按照顺序堆叠而成。每个层的输入都来自上一层的输出,形成了一种线性的堆叠结构。

Sequential模型适用于简单的线性堆叠网络,如全连接神经网络。然而,通过堆叠不同种类的层,Sequential模型也可以构建出更复杂的神经网络,如卷积神经网络(CNN)和循环神经网络(RNN)等。

在Sequential模型中,每一层都拥有一个唯一的输入tensor和输出tensor。通过不同层的堆叠,可以构建出神经网络。这种模型结构易于理解和调试,是初学者学习神经网络和深度学习的一个很好的起点。

要创建一个Sequential模型,可以使用tf.keras.Sequential()函数。然后,可以使用add()方法向模型中添加层,或者使用其他方式来构建模型的结构。一旦模型的结构定义好,就可以使用compile()方法来配置模型的学习过程,包括指定优化器、损失函数和评估指标等。

2、使用Sequential模型

2.1 配置

import keras
from keras import layers
from keras import ops

2.2 Sequential模型的适用场合

当使用顺序堆叠的层,且每一层都恰好有一个输入tensor和一个输出tensor时,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 = ops.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 = ops.ones((3, 3))
y = layer3(layer2(layer1(x)))

Sequential模型在以下情况下不适用:

  1. 你的模型有多个输入或多个输出。Sequential模型只支持单一输入和单一输出。

  2. 你的任何一层有多个输入或多个输出。在Sequential模型中,每一层都只能有一个输入tensor和一个输出tensor。

  3. 你需要进行层共享。Sequential模型不支持层之间的复杂连接,比如将同一个层应用于模型的不同部分。

  4. 你想要非线性的拓扑结构。例如,你希望在模型中实现残差连接(residual connections)或多分支模型(multi-branch models),这些结构无法在Sequential模型中直接实现。

3、如何使用Sequential模型

3.1 构建Sequential模型

你可以通过向Sequential构造函数传递一个层(layer)列表来创建一个Sequential模型。在Keras中,这通常是通过将多个层实例添加到列表中,然后将这个列表传递给Sequential类来实现的。

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

在Keras中,当你创建了一个Sequential模型后,你可以通过layers属性来访问这个模型中的各个层。layers属性是一个Python列表,包含了模型中按添加顺序排列的所有层实例。

from keras.models import Sequential  
from keras.layers import Dense  
  
# 创建一个Sequential模型  
model = Sequential([  
    Dense(64, activation='relu', input_shape=(784,)),  
    Dense(10, activation='softmax')  
])  
  
# 访问模型的层  
for layer in model.layers:  
    print(layer.name)  # 打印层的名字  
    print(layer.output_shape)  # 打印层的输出形状  
    # 你还可以访问其他层的属性,如 layer.input_shape, layer.weights 等  
  
# 如果你知道具体要访问哪一层,你也可以通过索引来访问  
first_layer = model.layers[0]  
print(first_layer.name)  # 输出第一层的名字

你还可以使用add()方法来增量地构建Sequential模型。这种方法允许你逐步添加层,非常适合在编写代码时逐步定义模型结构。

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

Sequential模型的行为非常类似于一个层列表,因为它也提供了pop()方法来移除层。如果你需要动态地修改模型的结构,可以通过pop()方法来移除已经添加的层。

from keras.models import Sequential  
from keras.layers import Dense  
  
# 创建一个Sequential模型并添加一些层  
model = Sequential()  
model.add(Dense(64, activation='relu', input_shape=(input_dim,)))  
model.add(Dense(32, activation='relu'))  
model.add(Dense(10, activation='softmax'))  
  
# 显示模型结构  
model.summary()  
  
# 移除最后一层  
model.pop()  
  
# 再次显示模型结构,你会看到最后一层已经被移除了  
model.summary()

Sequential构造函数接受一个name参数,就像任何其他层或模型一样。这个参数用于给模型一个有意义的名称,这在TensorBoard等可视化工具中特别有用,可以帮助你更清晰地理解和管理你的模型。

from keras.models import Sequential  
from keras.layers import Dense  
  
# 创建一个带有名称的Sequential模型  
model = Sequential(name='my_sequential_model')  
  
# 添加层  
model.add(Dense(64, activation='relu', input_shape=(input_dim,)))  
model.add(Dense(10, activation='softmax'))  
  
# 编译模型  
model.compile(optimizer='adam',  
              loss='categorical_crossentropy',  
              metrics=['accuracy'])  
  
# 现在你可以使用TensorBoard或其他可视化工具来查看和跟踪名为'my_sequential_model'的模型  
# ...

在Keras中,通常所有的层都需要知道其输入的形状,以便能够创建相应的权重。因此,当你像这样创建一个层时,它最初是没有权重的。

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

当一个层第一次在输入数据上被调用时,它才会创建其权重,因为权重的形状取决于输入数据的形状。

# Call layer on a test input
x = ops.ones((1, 4))
y = layer(x)
layer.weights  # Now it has weights, of shape (4, 3) and (3,)
[<KerasVariable shape=(4, 3), dtype=float32, path=dense_6/kernel>,
 <KerasVariable shape=(3,), dtype=float32, path=dense_6/bias>]

当然,这也适用于Sequential模型。当你实例化一个Sequential模型但没有指定输入形状时,该模型是“未构建”的:它没有权重(尝试调用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 = ops.ones((1, 4))
y = model(x)
print("Number of weights after calling the model:", len(model.weights))  # 6

一旦模型被“构建”,你就可以调用其summary()方法来显示其内容。

from keras.models import Sequential  
from keras.layers import Dense  
  
# 创建一个Sequential模型并指定输入形状  
model = Sequential()  
model.add(Dense(64, activation='relu', input_shape=(32,)))  
model.add(Dense(10, activation='softmax'))  
  
# 构建模型(在这个例子中,由于已经指定了input_shape,所以模型在添加层时就已经被构建了)  
# 如果你没有指定input_shape,可以调用 model.build(input_shape=(None, 32)) 来手动构建模型  
  
# 打印模型的摘要  
model.summary()

然而,在逐步构建Sequential模型时,能够显示到目前为止的模型摘要(包括当前输出形状)可能会非常有用。在这种情况下,你应该通过向模型传递一个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 (40.00 B)
 Trainable params: 10 (40.00 B)
 Non-trainable params: 0 (0.00 B)

使用预定义的输入形状构建的模型总是具有权重(甚至在看到任何数据之前),并且总是具有定义的输出形状。

一般来说,如果你知道输入的形状是什么,推荐的最佳实践是始终提前指定Sequential模型的输入形状。

3.2 使用add()+summary()调试

在构建新的Sequential架构时,通过增量地使用add()方法来堆叠层,并经常打印模型摘要(使用summary()方法),是一种常见的调试工作流程。例如,这可以让你监控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_5"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┓
┃ Layer (type)                    ┃ Output Shape              ┃    Param # ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━┩
│ conv2d (Conv2D)                 │ (None, 123, 123, 32)      │      2,432 │
├─────────────────────────────────┼───────────────────────────┼────────────┤
│ conv2d_1 (Conv2D)               │ (None, 121, 121, 32)      │      9,248 │
├─────────────────────────────────┼───────────────────────────┼────────────┤
│ max_pooling2d (MaxPooling2D)    │ (None, 40, 40, 32)        │          0 │
└─────────────────────────────────┴───────────────────────────┴────────────┘
 Total params: 11,680 (45.62 KB)
 Trainable params: 11,680 (45.62 KB)
 Non-trainable params: 0 (0.00 B)
Model: "sequential_5"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┓
┃ Layer (type)                    ┃ Output Shape              ┃    Param # ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━┩
│ conv2d (Conv2D)                 │ (None, 123, 123, 32)      │      2,432 │
├─────────────────────────────────┼───────────────────────────┼────────────┤
│ conv2d_1 (Conv2D)               │ (None, 121, 121, 32)      │      9,248 │
├─────────────────────────────────┼───────────────────────────┼────────────┤
│ max_pooling2d (MaxPooling2D)    │ (None, 40, 40, 32)        │          0 │
├─────────────────────────────────┼───────────────────────────┼────────────┤
│ conv2d_2 (Conv2D)               │ (None, 38, 38, 32)        │      9,248 │
├─────────────────────────────────┼───────────────────────────┼────────────┤
│ conv2d_3 (Conv2D)               │ (None, 36, 36, 32)        │      9,248 │
├─────────────────────────────────┼───────────────────────────┼────────────┤
│ max_pooling2d_1 (MaxPooling2D)  │ (None, 12, 12, 32)        │          0 │
├─────────────────────────────────┼───────────────────────────┼────────────┤
│ conv2d_4 (Conv2D)               │ (None, 10, 10, 32)        │      9,248 │
├─────────────────────────────────┼───────────────────────────┼────────────┤
│ conv2d_5 (Conv2D)               │ (None, 8, 8, 32)          │      9,248 │
├─────────────────────────────────┼───────────────────────────┼────────────┤
│ max_pooling2d_2 (MaxPooling2D)  │ (None, 4, 4, 32)          │          0 │
└─────────────────────────────────┴───────────────────────────┴────────────┘
 Total params: 48,672 (190.12 KB)
 Trainable params: 48,672 (190.12 KB)
 Non-trainable params: 0 (0.00 B)

3.3 使用Sequential模型进行特征提取

一旦Sequential模型被构建,它的行为就像是一个Functional API模型。这意味着每一层都有一个输入和输出属性。这些属性可以用来做一些有趣的事情,比如快速创建一个模型,该模型可以提取Sequential模型中所有中间层的输出。

from keras.models import Model  
from keras.layers import Input, Conv2D, MaxPooling2D, Flatten, Dense  
  
# 假设我们已经有了一个Sequential模型  
original_model = Sequential()  
original_model.add(Conv2D(32, (3, 3), activation='relu', input_shape=(32, 32, 3)))  
original_model.add(MaxPooling2D(pool_size=(2, 2)))  
original_model.add(Conv2D(64, (3, 3), activation='relu'))  
original_model.add(MaxPooling2D(pool_size=(2, 2)))  
original_model.add(Flatten())  
original_model.add(Dense(64, activation='relu'))  
original_model.add(Dense(10, activation='softmax'))  
  
# 我们想要提取第二个Conv2D层的输出作为特征  
# 我们需要获取原始模型的输入层  
input_tensor = original_model.layers[0].input  
  
# 我们需要创建一个新的模型,该模型将原始模型的输入作为输入,  
# 并输出我们想要的层的输出(在这个例子中是第二个Conv2D层)  
layer_dict = dict([(layer.name, layer) for layer in original_model.layers])  
feature_extraction_model = Model(inputs=input_tensor,   
                                 outputs=layer_dict['conv2d_2'].output)  
  
# 现在,我们可以使用feature_extraction_model来提取特征了  
# 假设我们有一些输入数据x_test  
# features = feature_extraction_model.predict(x_test)  
  
# 注意:层的名字(比如'conv2d_2')可能因Keras版本或模型构建方式的不同而有所变化  
# 你应该使用适合你的模型的正确层名

 仅从一层提取特征的相似示例如下:

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 = ops.ones((1, 250, 250, 3))
features = feature_extractor(x)

3.3 使用Sequential模型进行迁移学习

迁移学习涉及冻结模型中的底层(基础层)并仅训练顶层。以下是涉及Sequential模型的两种常见迁移学习蓝图。首先,假设你有一个Sequential模型,并且你想要冻结除最后一层之外的所有层。在这种情况下,你只需要遍历模型的层(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(...)

另一个常见的蓝图是使用Sequential模型来堆叠一个预训练模型和一些新初始化的分类层。

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MUKAMO

你的鼓励是我们创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值