Tensorflow 有没有办法将keras MobileNet V2模型划分为子模型?
我试图将Tensorflow 有没有办法将keras MobileNet V2模型划分为子模型?,tensorflow,keras,tensorflow2.0,mobilenet,Tensorflow,Keras,Tensorflow2.0,Mobilenet,我试图将mobilenetw2模型分为两部分 我首先要运行模型的第一部分,保存输出,然后出于某些原因将其提供给第二个模型。我试过找到代码, 但我得到了以下错误: ValueError: A merge layer should be called on a list of inputs. 我认为这是因为模型不是顺序的。 有人能帮忙吗?正如我在评论中提到的,mobile_net_v2中的某些层需要多个输入,而这些输入是之前某些层的输出。因此,将它们单独添加到序列模型会导致错误。我有另一个解决方案
mobilenetw2
模型分为两部分
我首先要运行模型的第一部分,保存输出,然后出于某些原因将其提供给第二个模型。我试过找到代码,
但我得到了以下错误:
ValueError: A merge layer should be called on a list of inputs.
我认为这是因为模型不是顺序的。
有人能帮忙吗?正如我在评论中提到的,mobile_net_v2中的某些层需要多个输入,而这些输入是之前某些层的输出。因此,将它们单独添加到序列模型会导致错误。我有另一个解决方案给你。使用link中的mobile_net_v2实现(我自己的),我能够创建您想要的模型:
import tensorflow as tf
from tensorflow.keras import layers, Model, Sequential
def conv_block(input_tensor, c, s, t, expand=True):
"""
Convolutional Block for mobile net v2
Args:
input_tensor (keras tensor): input tensor
c (int): output channels
s (int): stride size of first layer in the series
t (int): expansion factor
expand (bool): expand filters or not?
Returns: keras tensor
"""
first_conv_channels = input_tensor.get_shape()[-1]
if expand:
x = layers.Conv2D(
first_conv_channels*t,
1,
1,
padding='same',
use_bias=False
)(input_tensor)
x = layers.BatchNormalization()(x)
x = layers.ReLU(6.0)(x)
else:
x = input_tensor
x = layers.DepthwiseConv2D(
3,
s,
'same',
1,
use_bias=False
)(x)
x = layers.BatchNormalization()(x)
x = layers.ReLU(6.0)(x)
x = layers.Conv2D(
c,
1,
1,
padding='same',
use_bias=False
)(x)
x = layers.BatchNormalization()(x)
if input_tensor.get_shape() == x.get_shape() and s == 1:
return x+input_tensor
return x
def splitted_model(input_shape=(224,224,3)):
input = layers.Input(shape=input_shape)
x = layers.Conv2D(
32,
3,
2,
padding='same',
use_bias=False
)(input)
x = layers.BatchNormalization()(x)
x = layers.ReLU(6.0)(x)
x = conv_block(x, 16, 1, 1, expand=False)
x = conv_block(x, 24, 2, 6)
x = conv_block(x, 24, 1, 6)
x = conv_block(x, 32, 2, 6)
x = conv_block(x, 32, 1, 6)
x = conv_block(x, 32, 1, 6)
x = conv_block(x, 64, 2, 6)
x = conv_block(x, 64, 1, 6)
x = conv_block(x, 64, 1, 6)
x = conv_block(x, 64, 1, 6)
model_f = Model(inputs=input, outputs=x)
input_2 = layers.Input(shape=(x.shape[1:]))
x = conv_block(input_2, 96, 1, 6)
x = conv_block(x, 96, 1, 6)
x = conv_block(x, 96, 1, 6)
x = conv_block(x, 160, 2, 6)
x = conv_block(x, 160, 1, 6)
x = conv_block(x, 160, 1, 6)
x = conv_block(x, 320, 1, 6)
x = layers.Conv2D(
1280,
1,
1,
padding='same',
use_bias=False
)(x)
x = layers.BatchNormalization()(x)
x = layers.ReLU(6.0)(x)
x = layers.GlobalAveragePooling2D()(x)
model_h = Model(inputs=input_2, outputs=x)
return model_f, model_h
您可以创建以下两个模型:
IMG_SIZE = 160
IMG_SHAPE = (IMG_SIZE, IMG_SIZE, 3)
model_f, model_h = splitted_model(input_shape=IMG_SHAPE)
请注意,权重是随机初始化的。如果要在imagenet上训练mobilenet_v2中的权重,可以运行以下代码来复制权重:
mobile_net = tf.keras.applications.MobileNetV2(input_shape=IMG_SHAPE,
include_top=False,
weights='imagenet')
layer_f_counter = 0
layer_h_counter = 0
for i in range(len(mobile_net.layers)):
if layer_f_counter<len(model_f.layers):
if len(mobile_net.layers[i].get_weights()) > 0:
if len(model_f.layers[layer_f_counter].get_weights()) > 0:
print(mobile_net.layers[i].name,'here', model_f.layers[layer_f_counter].name, layer_f_counter)
model_f.layers[layer_f_counter].set_weights(mobile_net.layers[i].get_weights())
layer_f_counter += 1
print(layer_f_counter)
else:
if len(model_f.layers[layer_f_counter].get_weights()) > 0:
continue
else:
layer_f_counter+=1
else:
if layer_h_counter<len(model_h.layers):
if len(mobile_net.layers[i].get_weights()) > 0:
if len(model_h.layers[layer_h_counter].get_weights()) > 0:
print(mobile_net.layers[i].name,'here', model_h.layers[layer_h_counter].name, layer_h_counter)
model_h.layers[layer_h_counter].set_weights(mobile_net.layers[i].get_weights())
layer_h_counter += 1
print(layer_h_counter)
else:
if len(model_h.layers[layer_h_counter].get_weights()) > 0:
continue
else:
layer_h_counter+=1
同样适用于型号h:
print(model_h.layers[-4].get_weights()) # printing weights of last conv layer in model_h
print(mobile_net.get_layer('Conv_1').get_weights()) # printing weights of last conv layer in mobile_net
请注意,我随机选择了要将莫尔_网分为模型f和模型h的块,您可以对其进行编辑以更改要拆分的位置。希望有帮助。你能分享你试图合并两个层的那一行吗(即,导致错误的那一行)?我想当我添加它时,使用下面的一行:
model\u h.add(model.layers[current\u layer])
。感谢您的快速响应。如果您使用了您提到的链接中的代码,它应该可以工作。我假设问题出在您试图拆分mobilenetv2
的地方。并非所有Mobilenet层都是连续的,也不是所有层都将单个层的输出作为输入。一些层获取多个层的输出并合并它们。确保拆分mobilenetv2时,第二部分希望将单个层的输出作为输入,而不是多个层。没有看到你的代码,这就是我现在所有的假设。谢谢你的回答。请问我可以在哪一层进行拆分,以及如何在该层进行拆分?到谷歌colab文件。提前谢谢你巴希尔!好的,我可以拆分它,直到层块2添加(层27,见colab笔记本)。这是连接到多个层的第一个层。在这层之后我再也不能分裂了。有人知道这个问题吗?谢谢!我以后再试试!与原始模型相比,我是否可能得到更多错误的预测?我是否需要编译模型?因为我有一个问题,就是每个输入都有相同的预测?我对第一个进行预测,并将输出用作第二个的输入。我还添加了一个密集的softmax层,因为我的原始模型也有。如果你使用从经过训练的mobile_net模型复制的层,你不需要编译,但是如果你添加了密集层,它会随机初始化权重,因此你必须编译和训练。是的,我有一个带有mobilenet基础模型的模型,我添加了一个密集层,训练模型并保存它。然后我导入这个模型,并使用您发布的代码加载权重。我还在分裂的_模型函数中添加了稠密层,但仍然得到错误的预测。我做错了什么,因为密集层的重量也被加载了吗?使用基本模型培训的PS:tf.keras.applications.MobileNetV2(输入\u shape=IMG\u shape,包括\u top=False,weights='imagenet'),class=2)
print(model_h.layers[-4].get_weights()) # printing weights of last conv layer in model_h
print(mobile_net.get_layer('Conv_1').get_weights()) # printing weights of last conv layer in mobile_net