Tensorflow 和 Keras 的迁移学习问题
Issue with transfer learning with Tensorflow and Keras
我一直在尝试重新创建在 this blog post. The writeup is very comprehensive and code 中完成的工作是通过协作共享的。
我想做的是从预训练的 VGG19 网络中提取层,并创建一个将这些层作为输出的新网络。然而,当我 assemble 新网络时,它与 VGG19 网络非常相似,并且似乎包含我没有提取的层。下面是一个例子。
import tensorflow as tf
from tensorflow.python.keras import models
## Create network based on VGG19 arch with pretrained weights
vgg = tf.keras.applications.vgg19.VGG19(include_top=False, weights='imagenet')
vgg.trainable = False
当我们查看 VGG19 的摘要时,我们看到了我们期望的架构。
vgg.summary()
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_2 (InputLayer) (None, None, None, 3) 0
_________________________________________________________________
block1_conv1 (Conv2D) (None, None, None, 64) 1792
_________________________________________________________________
block1_conv2 (Conv2D) (None, None, None, 64) 36928
_________________________________________________________________
block1_pool (MaxPooling2D) (None, None, None, 64) 0
_________________________________________________________________
block2_conv1 (Conv2D) (None, None, None, 128) 73856
_________________________________________________________________
block2_conv2 (Conv2D) (None, None, None, 128) 147584
_________________________________________________________________
block2_pool (MaxPooling2D) (None, None, None, 128) 0
_________________________________________________________________
block3_conv1 (Conv2D) (None, None, None, 256) 295168
_________________________________________________________________
block3_conv2 (Conv2D) (None, None, None, 256) 590080
_________________________________________________________________
block3_conv3 (Conv2D) (None, None, None, 256) 590080
_________________________________________________________________
block3_conv4 (Conv2D) (None, None, None, 256) 590080
_________________________________________________________________
block3_pool (MaxPooling2D) (None, None, None, 256) 0
_________________________________________________________________
block4_conv1 (Conv2D) (None, None, None, 512) 1180160
_________________________________________________________________
block4_conv2 (Conv2D) (None, None, None, 512) 2359808
_________________________________________________________________
block4_conv3 (Conv2D) (None, None, None, 512) 2359808
_________________________________________________________________
block4_conv4 (Conv2D) (None, None, None, 512) 2359808
_________________________________________________________________
block4_pool (MaxPooling2D) (None, None, None, 512) 0
_________________________________________________________________
block5_conv1 (Conv2D) (None, None, None, 512) 2359808
_________________________________________________________________
block5_conv2 (Conv2D) (None, None, None, 512) 2359808
_________________________________________________________________
block5_conv3 (Conv2D) (None, None, None, 512) 2359808
_________________________________________________________________
block5_conv4 (Conv2D) (None, None, None, 512) 2359808
_________________________________________________________________
block5_pool (MaxPooling2D) (None, None, None, 512) 0
=================================================================
Total params: 20,024,384
Trainable params: 0
Non-trainable params: 20,024,384
_________________________________________________________________
然后,我们提取层并创建一个新模型
## Layers to extract
content_layers = ['block5_conv2']
style_layers = ['block1_conv1','block2_conv1','block3_conv1','block4_conv1','block5_conv1']
## Get output layers corresponding to style and content layers
style_outputs = [vgg.get_layer(name).output for name in style_layers]
content_outputs = [vgg.get_layer(name).output for name in content_layers]
model_outputs = style_outputs + content_outputs
new_model = models.Model(vgg.input, model_outputs)
当 new_model
创建时,我相信我们应该有一个更小的模型。但是,模型摘要显示新模型非常接近原始模型(它包含来自 VGG19 的 22 层中的 19 层)并且包含我们没有提取的层。
new_model.summary()
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_2 (InputLayer) (None, None, None, 3) 0
_________________________________________________________________
block1_conv1 (Conv2D) (None, None, None, 64) 1792
_________________________________________________________________
block1_conv2 (Conv2D) (None, None, None, 64) 36928
_________________________________________________________________
block1_pool (MaxPooling2D) (None, None, None, 64) 0
_________________________________________________________________
block2_conv1 (Conv2D) (None, None, None, 128) 73856
_________________________________________________________________
block2_conv2 (Conv2D) (None, None, None, 128) 147584
_________________________________________________________________
block2_pool (MaxPooling2D) (None, None, None, 128) 0
_________________________________________________________________
block3_conv1 (Conv2D) (None, None, None, 256) 295168
_________________________________________________________________
block3_conv2 (Conv2D) (None, None, None, 256) 590080
_________________________________________________________________
block3_conv3 (Conv2D) (None, None, None, 256) 590080
_________________________________________________________________
block3_conv4 (Conv2D) (None, None, None, 256) 590080
_________________________________________________________________
block3_pool (MaxPooling2D) (None, None, None, 256) 0
_________________________________________________________________
block4_conv1 (Conv2D) (None, None, None, 512) 1180160
_________________________________________________________________
block4_conv2 (Conv2D) (None, None, None, 512) 2359808
_________________________________________________________________
block4_conv3 (Conv2D) (None, None, None, 512) 2359808
_________________________________________________________________
block4_conv4 (Conv2D) (None, None, None, 512) 2359808
_________________________________________________________________
block4_pool (MaxPooling2D) (None, None, None, 512) 0
_________________________________________________________________
block5_conv1 (Conv2D) (None, None, None, 512) 2359808
_________________________________________________________________
block5_conv2 (Conv2D) (None, None, None, 512) 2359808
=================================================================
Total params: 15,304,768
Trainable params: 15,304,768
Non-trainable params: 0
_________________________________________________________________
所以我的问题是...
- 为什么
new_model
中出现了我没有提取的层。这些是由模型的实例化过程per the docs推断出来的吗?这似乎太接近 VGG19 架构,无法推断。
- 根据我对 Keras 的理解 Model (functional API),传递多个输出层应该会创建一个具有多个输出的模型,但是,新模型似乎是顺序的并且只有一个输出层。是这样吗?
- Why are layers that I didn't extract showing up in
new_model
.
那是因为当您使用 models.Model(vgg.input, model_outputs)
创建模型时,vgg.input
和输出层之间的 "intermediate" 层也包括在内。这是 VGG 以这种方式构建的预期方式。
例如,如果您要以这种方式创建模型:models.Model(vgg.input, vgg.get_layer('block2_pool')
input_1
和 block2_pool
之间的每个中间层都将被包括在内,因为输入 具有to 在到达 block2_pool
之前流经它们。下面是 VGG 的部分图表,可以帮助解决这个问题。
现在,-如果我没有误解的话- 如果您想创建一个不包含那些中间层(可能效果不佳)的模型,您必须自己创建一个。 Functional API 在这方面非常有用。 documentation 上有示例,但您要执行的操作的要点如下:
from keras.layers import Conv2D, Input
x_input = Input(shape=(28, 28, 1,))
block1_conv1 = Conv2D(64, (3, 3), padding='same')(x_input)
block2_conv2 = Conv2D(128, (3, 3), padding='same')(x_input)
...
new_model = models.Model(x_input, [block1_conv1, block2_conv2, ...])
- ... however, it seems that the new model is sequential and only has a single output layer. Is this the case?
不,您的模型如您所愿有多个输出。 model.summary()
应该显示哪些层连接到什么(这将有助于理解结构),但我相信某些版本存在一个小错误可以防止这种情况发生。在任何情况下,您都可以通过检查 new_model.output
看到您的模型有多个输出,这应该给您:
[<tf.Tensor 'block1_conv1/Relu:0' shape=(?, ?, ?, 64) dtype=float32>,
<tf.Tensor 'block2_conv1/Relu:0' shape=(?, ?, ?, 128) dtype=float32>,
<tf.Tensor 'block3_conv1/Relu:0' shape=(?, ?, ?, 256) dtype=float32>,
<tf.Tensor 'block4_conv1/Relu:0' shape=(?, ?, ?, 512) dtype=float32>,
<tf.Tensor 'block5_conv1/Relu:0' shape=(?, ?, ?, 512) dtype=float32>,
<tf.Tensor 'block5_conv2/Relu:0' shape=(?, ?, ?, 512) dtype=float32>]
在 new_model.summary()
中按顺序打印它只是一种设计选择,因为复杂的模型会变得很麻烦。
我一直在尝试重新创建在 this blog post. The writeup is very comprehensive and code 中完成的工作是通过协作共享的。
我想做的是从预训练的 VGG19 网络中提取层,并创建一个将这些层作为输出的新网络。然而,当我 assemble 新网络时,它与 VGG19 网络非常相似,并且似乎包含我没有提取的层。下面是一个例子。
import tensorflow as tf
from tensorflow.python.keras import models
## Create network based on VGG19 arch with pretrained weights
vgg = tf.keras.applications.vgg19.VGG19(include_top=False, weights='imagenet')
vgg.trainable = False
当我们查看 VGG19 的摘要时,我们看到了我们期望的架构。
vgg.summary()
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_2 (InputLayer) (None, None, None, 3) 0
_________________________________________________________________
block1_conv1 (Conv2D) (None, None, None, 64) 1792
_________________________________________________________________
block1_conv2 (Conv2D) (None, None, None, 64) 36928
_________________________________________________________________
block1_pool (MaxPooling2D) (None, None, None, 64) 0
_________________________________________________________________
block2_conv1 (Conv2D) (None, None, None, 128) 73856
_________________________________________________________________
block2_conv2 (Conv2D) (None, None, None, 128) 147584
_________________________________________________________________
block2_pool (MaxPooling2D) (None, None, None, 128) 0
_________________________________________________________________
block3_conv1 (Conv2D) (None, None, None, 256) 295168
_________________________________________________________________
block3_conv2 (Conv2D) (None, None, None, 256) 590080
_________________________________________________________________
block3_conv3 (Conv2D) (None, None, None, 256) 590080
_________________________________________________________________
block3_conv4 (Conv2D) (None, None, None, 256) 590080
_________________________________________________________________
block3_pool (MaxPooling2D) (None, None, None, 256) 0
_________________________________________________________________
block4_conv1 (Conv2D) (None, None, None, 512) 1180160
_________________________________________________________________
block4_conv2 (Conv2D) (None, None, None, 512) 2359808
_________________________________________________________________
block4_conv3 (Conv2D) (None, None, None, 512) 2359808
_________________________________________________________________
block4_conv4 (Conv2D) (None, None, None, 512) 2359808
_________________________________________________________________
block4_pool (MaxPooling2D) (None, None, None, 512) 0
_________________________________________________________________
block5_conv1 (Conv2D) (None, None, None, 512) 2359808
_________________________________________________________________
block5_conv2 (Conv2D) (None, None, None, 512) 2359808
_________________________________________________________________
block5_conv3 (Conv2D) (None, None, None, 512) 2359808
_________________________________________________________________
block5_conv4 (Conv2D) (None, None, None, 512) 2359808
_________________________________________________________________
block5_pool (MaxPooling2D) (None, None, None, 512) 0
=================================================================
Total params: 20,024,384
Trainable params: 0
Non-trainable params: 20,024,384
_________________________________________________________________
然后,我们提取层并创建一个新模型
## Layers to extract
content_layers = ['block5_conv2']
style_layers = ['block1_conv1','block2_conv1','block3_conv1','block4_conv1','block5_conv1']
## Get output layers corresponding to style and content layers
style_outputs = [vgg.get_layer(name).output for name in style_layers]
content_outputs = [vgg.get_layer(name).output for name in content_layers]
model_outputs = style_outputs + content_outputs
new_model = models.Model(vgg.input, model_outputs)
当 new_model
创建时,我相信我们应该有一个更小的模型。但是,模型摘要显示新模型非常接近原始模型(它包含来自 VGG19 的 22 层中的 19 层)并且包含我们没有提取的层。
new_model.summary()
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_2 (InputLayer) (None, None, None, 3) 0
_________________________________________________________________
block1_conv1 (Conv2D) (None, None, None, 64) 1792
_________________________________________________________________
block1_conv2 (Conv2D) (None, None, None, 64) 36928
_________________________________________________________________
block1_pool (MaxPooling2D) (None, None, None, 64) 0
_________________________________________________________________
block2_conv1 (Conv2D) (None, None, None, 128) 73856
_________________________________________________________________
block2_conv2 (Conv2D) (None, None, None, 128) 147584
_________________________________________________________________
block2_pool (MaxPooling2D) (None, None, None, 128) 0
_________________________________________________________________
block3_conv1 (Conv2D) (None, None, None, 256) 295168
_________________________________________________________________
block3_conv2 (Conv2D) (None, None, None, 256) 590080
_________________________________________________________________
block3_conv3 (Conv2D) (None, None, None, 256) 590080
_________________________________________________________________
block3_conv4 (Conv2D) (None, None, None, 256) 590080
_________________________________________________________________
block3_pool (MaxPooling2D) (None, None, None, 256) 0
_________________________________________________________________
block4_conv1 (Conv2D) (None, None, None, 512) 1180160
_________________________________________________________________
block4_conv2 (Conv2D) (None, None, None, 512) 2359808
_________________________________________________________________
block4_conv3 (Conv2D) (None, None, None, 512) 2359808
_________________________________________________________________
block4_conv4 (Conv2D) (None, None, None, 512) 2359808
_________________________________________________________________
block4_pool (MaxPooling2D) (None, None, None, 512) 0
_________________________________________________________________
block5_conv1 (Conv2D) (None, None, None, 512) 2359808
_________________________________________________________________
block5_conv2 (Conv2D) (None, None, None, 512) 2359808
=================================================================
Total params: 15,304,768
Trainable params: 15,304,768
Non-trainable params: 0
_________________________________________________________________
所以我的问题是...
- 为什么
new_model
中出现了我没有提取的层。这些是由模型的实例化过程per the docs推断出来的吗?这似乎太接近 VGG19 架构,无法推断。 - 根据我对 Keras 的理解 Model (functional API),传递多个输出层应该会创建一个具有多个输出的模型,但是,新模型似乎是顺序的并且只有一个输出层。是这样吗?
- Why are layers that I didn't extract showing up in
new_model
.
那是因为当您使用 models.Model(vgg.input, model_outputs)
创建模型时,vgg.input
和输出层之间的 "intermediate" 层也包括在内。这是 VGG 以这种方式构建的预期方式。
例如,如果您要以这种方式创建模型:models.Model(vgg.input, vgg.get_layer('block2_pool')
input_1
和 block2_pool
之间的每个中间层都将被包括在内,因为输入 具有to 在到达 block2_pool
之前流经它们。下面是 VGG 的部分图表,可以帮助解决这个问题。
现在,-如果我没有误解的话- 如果您想创建一个不包含那些中间层(可能效果不佳)的模型,您必须自己创建一个。 Functional API 在这方面非常有用。 documentation 上有示例,但您要执行的操作的要点如下:
from keras.layers import Conv2D, Input
x_input = Input(shape=(28, 28, 1,))
block1_conv1 = Conv2D(64, (3, 3), padding='same')(x_input)
block2_conv2 = Conv2D(128, (3, 3), padding='same')(x_input)
...
new_model = models.Model(x_input, [block1_conv1, block2_conv2, ...])
- ... however, it seems that the new model is sequential and only has a single output layer. Is this the case?
不,您的模型如您所愿有多个输出。 model.summary()
应该显示哪些层连接到什么(这将有助于理解结构),但我相信某些版本存在一个小错误可以防止这种情况发生。在任何情况下,您都可以通过检查 new_model.output
看到您的模型有多个输出,这应该给您:
[<tf.Tensor 'block1_conv1/Relu:0' shape=(?, ?, ?, 64) dtype=float32>,
<tf.Tensor 'block2_conv1/Relu:0' shape=(?, ?, ?, 128) dtype=float32>,
<tf.Tensor 'block3_conv1/Relu:0' shape=(?, ?, ?, 256) dtype=float32>,
<tf.Tensor 'block4_conv1/Relu:0' shape=(?, ?, ?, 512) dtype=float32>,
<tf.Tensor 'block5_conv1/Relu:0' shape=(?, ?, ?, 512) dtype=float32>,
<tf.Tensor 'block5_conv2/Relu:0' shape=(?, ?, ?, 512) dtype=float32>]
在 new_model.summary()
中按顺序打印它只是一种设计选择,因为复杂的模型会变得很麻烦。