问题
由于经常调用各种预训练模型,而这些模型又常常封装得太好,不好修改,一种办法是取出所需要的子模型作为层再进行拼接设计。当我采取如下方法得到子模型(基于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: []
解决办法
修改如下:
# 加载模型
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 类则必须重新建立 input 与 output 间的连接图,所以此处应调用 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即可