Keras实践-取一个模型中的子模型(模型分割)

问题

由于经常调用各种预训练模型,而这些模型又常常封装得太好,不好修改,一种办法是取出所需要的子模型作为层再进行拼接设计。当我采取如下方法得到子模型(基于keras-bert)后出错:

#加载模型
bert_model = load_trained_model_from_checkpoint(self.config_path, self.checkpoint_path)

#在Embedding-Position层分割成两个模型
model_sub1 = Model(inputs=bert_model.input, outputs=bert_model.get_layer(name='Embedding-Position').output)
#     第二个子模型
model_sub2 = Model(inputs=bert_model.get_layer(name='Embedding-Dropout').input, outputs=bert_model.output)

#两个模型中插入新的层
x1 = model_sub1([x_ind, x_seg])
x2=GaussianNoise(0.15)(x1)    #新层
x3=model_sub2(x2)
报错:

Graph disconnected: cannot obtain value for tensor Tensor( ) at layer " ". The following previous layers were accessed without issue: []

解决办法

参考 https://stackoverflow.com/questions/56147685/how-to-split-a-keras-model-with-a-non-sequential-architecture-like-resnet-into?r=SearchResults

修改如下:

# 加载模型
bert_model = load_trained_model_from_checkpoint(self.config_path, self.checkpoint_path)

# 在Embedding-Position层分割成两个模型
model_sub1 = Model(inputs=bert_model.input, outputs=bert_model.get_layer(name='Embedding-Position').output)
#     第二个子模型
new_input = Input(batch_shape=bert_model.get_layer(name='Embedding-Dropout').get_input_shape_at(0))
new_output = get_output_of_layer(bert_model.layers[-1])
model_sub2 = Model(inputs=new_input, outputs=new_output)

# 两个模型中插入新的层
x1 = model_sub1([x_ind, x_seg])
x2 = GaussianNoise(0.15)(x1)  # 新层
x3 = model_sub2(x2)

原因

代码在第二个子模型处报错,原因是因为模型的inputs应该为 keras.Input 类,而创建新的 Input 类则必须重新建立 inputoutput 间的连接图,所以此处应调用 get_output_of_layer 方法,递归建立input与output的联系。

#记录计算过的层
layer_outputs = {}
#返回当前层的output
def get_output_of_layer(layer):
    # 1、如果已经计算过则直接返回output
    if layer.name in layer_outputs:
        return layer_outputs[layer.name]

    # 2、如果回溯到input节点则通过层计算output
    if layer.name == starting_layer_name:
        out = layer(new_input)
        layer_outputs[layer.name] = out
        return out

    # 3、找到当前层连接的所有输入层
    prev_layers = []
    for node in layer._inbound_nodes:
        prev_layers.extend(node.inbound_layers)

    # 递归得到所有前一层的output
    pl_outs = []
    for pl in prev_layers:
        pl_outs.extend([get_output_of_layer(pl)])

    # 通过得到的output计算当前层output
    out = layer(pl_outs[0] if len(pl_outs) == 1 else pl_outs)
    layer_outputs[layer.name] = out
    return out

最后将建立节点关系的output输入给model即可

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
当然可以!以下是一个基于Keras的DeepLabV3+语义分割三分类模型的示例代码: ```python from tensorflow.keras.models import Model from tensorflow.keras.layers import Input, Conv2D, BatchNormalization, Activation, MaxPooling2D, Conv2DTranspose, concatenate def conv_block(inputs, filters, kernel_size=3, strides=1): x = Conv2D(filters, kernel_size, strides=strides, padding='same')(inputs) x = BatchNormalization()(x) x = Activation('relu')(x) return x def encoder(inputs): # Encoder block 1 x = conv_block(inputs, 64) x = conv_block(x, 64) skip_1 = x x = MaxPooling2D(pool_size=(2, 2))(x) # Encoder block 2 x = conv_block(x, 128) x = conv_block(x, 128) skip_2 = x x = MaxPooling2D(pool_size=(2, 2))(x) # Encoder block 3 x = conv_block(x, 256) x = conv_block(x, 256) skip_3 = x x = MaxPooling2D(pool_size=(2, 2))(x) return x, skip_1, skip_2, skip_3 def decoder(inputs, skip_1, skip_2, skip_3): # Decoder block 1 x = Conv2DTranspose(128, (3, 3), strides=(2, 2), padding='same')(inputs) x = concatenate([x, skip_3]) x = conv_block(x, 256) x = conv_block(x, 256) # Decoder block 2 x = Conv2DTranspose(64, (3, 3), strides=(2, 2), padding='same')(x) x = concatenate([x, skip_2]) x = conv_block(x, 128) x = conv_block(x, 128) # Decoder block 3 x = Conv2DTranspose(32, (3, 3), strides=(2, 2), padding='same')(x) x = concatenate([x, skip_1]) x = conv_block(x, 64) x = conv_block(x, 64) return x def DeepLabV3Plus(input_shape, num_classes): inputs = Input(shape=input_shape) # Encoder encoder_output, skip_1, skip_2, skip_3 = encoder(inputs) # ASPP (Atrous Spatial Pyramid Pooling) x = conv_block(encoder_output, 256, kernel_size=1) x = conv_block(x, 256, kernel_size=3, strides=1, dilation_rate=6) x = conv_block(x, 256, kernel_size=3, strides=1, dilation_rate=12) x = conv_block(x, 256, kernel_size=3, strides=1, dilation_rate=18) x = Conv2D(256, 1)(x) x = BatchNormalization()(x) # Decoder x = decoder(x, skip_1, skip_2, skip_3) # Output outputs = Conv2D(num_classes, 1, activation='softmax')(x) model = Model(inputs=inputs, outputs=outputs) return model # 创建模型 input_shape = (256, 256, 3) # 输入图像的尺寸 num_classes = 3 # 分类的类别数量 model = DeepLabV3Plus(input_shape, num_classes) # 编译模型 model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy']) # 打印模型结构 model.summary() ``` 这段代码实现了一个简单的DeepLabV3+语义分割模型,具有三个分类类别。你可以根据自己的需求修改模型的输入尺寸、分类数量以及其他超参数。记得根据你的数据集调整模型的输入尺寸和输出类别数量。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值