如何显示预训练模型的层而不是 model.summary() 输出中的单个条目?

Posted

技术标签:

【中文标题】如何显示预训练模型的层而不是 model.summary() 输出中的单个条目?【英文标题】:How to display the layers of a pretrained model instead of a single entry in model.summary() output? 【发布时间】:2021-09-28 11:24:08 【问题描述】:

由于标题清楚地描述了问题,我想在model.summary() 函数输出中显示预保留模型的层而不是单个条目(请参阅下面的vgg19 (Functional) 条目)?

这是一个使用Keras Sequential API 实现的示例模型:

base_model = VGG16(include_top=False, weights=None, input_shape=(32, 32, 3), pooling='max', classes=10)
model = Sequential()
model.add(base_model)
model.add(Flatten())
model.add(Dense(1_000, activation='relu'))
model.add(Dense(10, activation='softmax'))

这是model.summary()函数调用的输出:

Model: "sequential_15"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
vgg19 (Functional)           (None, 512)               20024384  
_________________________________________________________________
flatten_15 (Flatten)         (None, 512)               0         
_________________________________________________________________
dense_21 (Dense)             (None, 1000)              513000    
_________________________________________________________________
dense_22 (Dense)             (None, 10)                10010     
=================================================================
Total params: 20,547,394
Trainable params: 523,010
Non-trainable params: 20,024,384

编辑:这是实现 Sequential API 模型的 Functional API 等效项 - 结果是相同的:

base_model = VGG16(include_top=False, weights='imagenet', input_shape=(32, 32, 3), pooling='max', classes=10)

m_inputs = Input(shape=(32, 32, 3))
base_out = base_model(m_inputs)
x = Flatten()(base_out)
x = Dense(1_000, activation='relu')(x)
m_outputs = Dense(10, activation='softmax')(x)

model = Model(inputs=m_inputs, outputs=m_outputs)

【问题讨论】:

如果你想将一个预训练模型层展平到你的模型中,你应该强制 tf 在创建模型时通过预训练模型层。怎么做?好吧,您应该将其作为输入或输出添加到模型定义行中。然后,为了在您的输入层和输出层之间创建连接,它必须经过内部层,否则它将在您的新模型中将其视为单个层。 【参考方案1】:

通过文档并运行一些测试(通过 TF 2.5.0)后,我的理解是,当这样的模型包含在另一个模型中时,Keras 将其视为“黑匣子”。它不是一个简单的层,绝对没有张量,基本上是复杂类型的tensorflow.python.keras.engine.functional.Functional

我认为这是您无法将其详细打印出来作为模型摘要的一部分的根本原因。

    现在,如果您只想查看预训练模型、先睹为快等,您可以简单地运行:
base_model.summary()

或在构建模型之后(顺序或函数,此时无关紧要):

model.layers[i].summary() # i: the index of your pre-trained model

如果您需要访问预训练模型的层,例如要单独使用其权重等,您也可以通过这种方式访问​​它们。


    如果您想作为一个整体打印模型的层,那么您需要欺骗 Keras,让其相信“黑匣子”并不陌生,而只是另一个 KerasTensor。为此,您可以将预训练模型包装在另一层中 - 换句话说,通过功能 API 直接连接它们 - 建议 above 并且对我来说效果很好。
x = tf.keras.layers.Flatten()( base_model.output )

我不知道您是否有任何具体原因想要像在...中那样追求新的输入路线

m_inputs = 输入(shape=(32, 32, 3))

base_out = base_model(m_inputs)

每当您在新模型的中间找到预训练模型时,例如在新输入层之后或将其添加到序列模型本身,其中的层将从摘要输出中消失。

在这种情况下,生成一个新的输入层或只是将预训练模型的输出作为输入提供给当前模型对我没有任何影响。

希望这能进一步阐明主题,并有所帮助。

【讨论】:

【参考方案2】:

这应该做你想做的事

base_model = VGG16(include_top=False, weights=None, input_shape=(32, 32, 3), pooling='max', classes=10)

model = Sequential()

for layer in base_model.layers:
   layer.trainable = False
   model.add(layer)

model.add(Flatten())
model.add(Dense(1_000, activation='relu'))
model.add(Dense(10, activation='softmax'))

【讨论】:

【参考方案3】:

我没有使用Sequential,而是尝试使用Functional API,即tf.keras.models.Model类,比如,

import tensorflow as tf

base_model = tf.keras.applications.VGG16(include_top=False, weights=None, input_shape=(32, 32, 3), pooling='max', classes=10)
x = tf.keras.layers.Flatten()( base_model.output )
x = tf.keras.layers.Dense(1_000, activation='relu')( x )
outputs = tf.keras.layers.Dense(10, activation='softmax')( x )

model = tf.keras.models.Model( base_model.input , outputs )
model.summary()

上面sn-p的输出,

Model: "model"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_3 (InputLayer)         [(None, 32, 32, 3)]       0         
_________________________________________________________________
block1_conv1 (Conv2D)        (None, 32, 32, 64)        1792      
_________________________________________________________________
block1_conv2 (Conv2D)        (None, 32, 32, 64)        36928     
_________________________________________________________________
block1_pool (MaxPooling2D)   (None, 16, 16, 64)        0         
_________________________________________________________________
block2_conv1 (Conv2D)        (None, 16, 16, 128)       73856     
_________________________________________________________________
block2_conv2 (Conv2D)        (None, 16, 16, 128)       147584    
_________________________________________________________________
block2_pool (MaxPooling2D)   (None, 8, 8, 128)         0         
_________________________________________________________________
block3_conv1 (Conv2D)        (None, 8, 8, 256)         295168    
_________________________________________________________________
block3_conv2 (Conv2D)        (None, 8, 8, 256)         590080    
_________________________________________________________________
block3_conv3 (Conv2D)        (None, 8, 8, 256)         590080    
_________________________________________________________________
block3_pool (MaxPooling2D)   (None, 4, 4, 256)         0         
_________________________________________________________________
block4_conv1 (Conv2D)        (None, 4, 4, 512)         1180160   
_________________________________________________________________
block4_conv2 (Conv2D)        (None, 4, 4, 512)         2359808   
_________________________________________________________________
block4_conv3 (Conv2D)        (None, 4, 4, 512)         2359808   
_________________________________________________________________
block4_pool (MaxPooling2D)   (None, 2, 2, 512)         0         
_________________________________________________________________
block5_conv1 (Conv2D)        (None, 2, 2, 512)         2359808   
_________________________________________________________________
block5_conv2 (Conv2D)        (None, 2, 2, 512)         2359808   
_________________________________________________________________
block5_conv3 (Conv2D)        (None, 2, 2, 512)         2359808   
_________________________________________________________________
block5_pool (MaxPooling2D)   (None, 1, 1, 512)         0         
_________________________________________________________________
global_max_pooling2d_2 (Glob (None, 512)               0         
_________________________________________________________________
flatten_1 (Flatten)          (None, 512)               0         
_________________________________________________________________
dense_2 (Dense)              (None, 1000)              513000    
_________________________________________________________________
dense_3 (Dense)              (None, 10)                10010     
=================================================================
Total params: 15,237,698
Trainable params: 15,237,698
Non-trainable params: 0
_________________________________________________________________

【讨论】:

非常感谢您的关心。请查看编辑后的 ​​OP,因为我提供了 Functional API 等效于我的 Sequential API 模型,结果仍然相同。

以上是关于如何显示预训练模型的层而不是 model.summary() 输出中的单个条目?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 HitTest 获得最前面的层而不是最深层

如果我们扩展或减少同一模型的层,我们仍然可以从 Pytorch 中的预训练模型进行训练吗?

如何在 Tensorflow 中设置分层学习率?

如何在 Tensorflow 中设置分层学习率?

pytorch中修改后的模型如何加载预训练模型

论文泛读137LV-BERT:利用 BERT 的层多样性