python - 为什么使用 Keras API 将最大池替换为平均池会失败?
问题描述
我正在尝试使用 Keras API 将预训练网络中的最大池层替换为平均池层。不知何故,它对我不起作用。如果您能帮助我弄清楚如何实施它,我将不胜感激。
以下是我目前的解决方案:
def replace_max_by_average_pooling(model):
input_layer, *other_layers = model.layers
assert isinstance(input_layer, keras.layers.InputLayer)
x = input_layer.output
for layer in other_layers:
if isinstance(layer, keras.layers.MaxPooling2D):
layer = keras.layers.AveragePooling2D(
pool_size=layer.pool_size,
strides=layer.strides,
padding=layer.padding,
data_format=layer.data_format,
name=f"{layer.name}_av",
)
x = layer(x)
return keras.models.Model(inputs=input_layer.input, outputs=x)
当我尝试在 VGG 网络上使用此功能时:
vgg = keras.applications.vgg19.VGG19(include_top=False, weights="imagenet")
vgg_av = replace_max_by_average_pooling(vgg)
如果我打印摘要,它看起来不错:
_________________________________________________________________ 层(类型)输出形状参数#
========================================= ======================== input_1 (InputLayer) (None, None, None, 3) 0
_________________________________________________________________ block1_conv1 (Conv2D) (None, None, None, 64)1792
_________________________________________________________________ block1_conv2(Conv2D)(无,无,无,64)36928
_________________________________________________________________ block1_pool_av(平均池(无,无,无,64)0
_________________________________________________________________ block2_conv1 (Conv2D) (无,无,无,128) 73856
_________________________________________________________________ block2_conv2 (Conv2D) (无,无,无,128) 147584
_________________________________________________________________ block2_pool_av (AveragePooli (无,无,无,128) 0
_________________________________________________________________ block3_conv1 (Conv2D)无,无,无,256)295168
...
但是,如果我尝试基于以下几层构建一个新模型vgg_av
:
layer = vgg_av.get_layer("block3_conv1")
keras.models.Model(inputs=vgg_av.layers[0].input, outputs=layer.output).summary()
不知何故,平均池层再次被最大池层取代:
_________________________________________________________________ 层(类型)输出形状参数#
========================================= ======================== input_1 (InputLayer) (None, None, None, 3) 0
_________________________________________________________________ block1_conv1 (Conv2D) (None, None, None, 64)1792
_________________________________________________________________ block1_conv2(Conv2D)(无,无,无,64)36928
_________________________________________________________________ block1_pool(MaxPooling2D) (无,无,无,64)0
_________________________________________________________________ block2_conv1 (Conv2D) (无,无,无,128) 73856
_________________________________________________________________ block2_conv2 (Conv2D) (无,无,无,128) 147584
_________________________________________________________________ block2_pool (MaxPooling2D) (无,无,无,128) 0
_________________________________________________________________ block3_conv1 (Conv2D) (无,无,无,256)295168
======================================== ========================= 总参数:555,328 可训练参数:555,328 不可训练参数:0
难道我做错了什么?为什么和在哪里?
我的猜测是,在这条线上,x = layer(x)
新操作被添加到计算图中,使得新操作具有 name *name of an old operation*_1
,并且当我调用vgg_av.get_layer("block3_conv1")
它时仍然从vgg
. 但如果我在 中打印图层名称vgg_av
,则名称与 中相同vgg
。为什么只有在我尝试获取图层子集时它才会失败?我想完全重建计算图,但也许我缺少一些 Keras API,或者我在概念上缺少一些东西。
解决方案
原因是每当您重用一个层(您在使用平均池创建新分支时重用层)时,您都会在图中创建一个新节点。
原始模型仍然存在,并且所有层都使用索引 0 的节点,而您的新模型使用索引 1 的节点。
层应该有方法get_output_at(index)
或类似的东西,你将要从中获取输出的节点传递给它。根据我过去的经验,我猜这只会layer.output
带来错误,因为您有多个节点(但令人惊讶的是,代码接受了这一点——我猜 keras 版本会有所不同)。
因此,您应该通过以下方式实现您的目标:
layer = vgg_av.get_layer("block3_conv1")
output = layer.get_output_at(1)
keras.models.Model(inputs=vgg_av.layers[0].input, outputs=output).summary()
.outputs
在调用最后一层后计算新模型的最后一层的数量应该是一个好主意replace_max_by_average_pooling
,以防您要从同一个原始模型中获得更多这样的模型(意味着更多节点)。
黑客建议
在 Keras 中保存和加载模型提供了一个系统(最初用于自定义层和自定义函数),您可以在其中定义 keras 应该为它不知道的类名和函数名使用什么。
加载模型是“使用保存的参数再次创建模型”。因此,如果您使用此系统“替换”现有名称,它应该可以在模型重建期间替换层。
custom_objects = {'MaxPooling2D': AveragePooling2D}
vgg.save_model(filename)
vgg_ag = keras.models.load_model(filename, custom_objects = custom_objects)
如果这不起作用,您可以创建一个自定义函数,使用给定的参数返回一个平均池,例如:
def createAvgFromMax(**params):
#study the params, choose what to keep and discard
return AveragePooling2D(....)
和custom_objects = { 'MaxPooling2D': createAvgFromMax }
推荐阅读
- react-native - React Native:基于 AsyncStorage 结果的条件渲染()
- python - python中的逻辑与运算
- python - 根据连续行之间的时间差标记重复项
- java - 如何在java中动态创建XML元素?
- c++ - 类元素加入的 C++ 自动迭代器向量
- amazon-web-services - react-native AWS PUBSUB无法重新连接
- docker - 在运行容器时,是否存在不应该使用 --init 的情况?
- java - 类必须声明为抽象的还是实现的?
- javascript - 有趣的递归 lambda 示例
- reactjs - 如何在构造函数中绑定事件处理程序并在 React 中使用参数调用它?