我想做的是:
我想连接不同模型的任意层来创建一个新的Keras模型。
我目前找到的:
https://github.com/keras-team/keras/issues/4205:使用模型的call类来改变另一个模型的输入。我对这种方法的问题:
- 只能改变模型的输入,不能改变其他层。所以如果我想在编码器的开始处切掉一些层,这是不可能的
- 我不喜欢在获取配置文件时使用的嵌套数组结构。更希望有一个一维数组
-
在使用model.summary()或plot_model()时,编码器只显示为“模型”。如果有的话,我认为应该将两个模型都包装起来。所以配置应该显示[model_base, model_encoder],而不是[base_input, base_conv2D, …, encoder_model]
-
公平地说,使用这种方法:https://github.com/keras-team/keras/issues/3021,上面的点实际上是可能的,但同样,它非常不灵活。一旦我想在基础或编码器网络的顶部或底部切掉一些层,这种方法就会失败
https://github.com/keras-team/keras/issues/3465:通过使用基础模型的任何输出,向基础模型添加新层。这里存在的问题:
- 虽然可以使用基础模型的任何层,这意味着我可以从基础模型中切掉层,但我不能将编码器加载为Keras模型。顶层模型总是必须新创建。
我尝试过的:
我连接不同模型的任意层的方法:
- 清除输入层的入边节点
- 使用输出层的call()方法与输出层的张量
- 通过用新创建的张量替换之前的输出张量,清理输出张量的出边节点
起初我非常乐观,因为summary()
和plot_model()
让我得到了我想要的结果,因此节点图应该没问题,对吗?但是在训练时我遇到了错误。虽然“目前找到的”部分中的方法训练得很好,但我使用自己的方法时遇到了错误。这是错误消息:
File "C:\Anaconda\envs\dlpipe\lib\site-packages\tensorflow\python\framework\op_def_library.py", line 508, in apply_op (input_name, err))ValueError: Tried to convert 'x' to a tensor and failed. Error: None values not supported.
可能是一个重要的信息,我使用TensorFlow作为后端。我能够追溯到这个错误的根源。似乎在计算梯度时出现了错误。通常,每个节点都会进行一次梯度计算,但使用我的方法时,基础网络的所有节点都是“None”。所以基本上在keras/optimizers.py中,get_updates()
在计算梯度时(grad = self.get_gradients(loss, params)
)。
这是没有训练的代码,实现了所有三种方法:
def create_base(): in_layer = Input(shape=(32, 32, 3), name="base_input") x = Conv2D(32, (3, 3), padding='same', activation="relu", name="base_conv2d_1")(in_layer) x = Conv2D(32, (3, 3), padding='same', activation="relu", name="base_conv2d_2")(x) x = MaxPooling2D(pool_size=(2, 2), name="base_maxpooling_2d_1")(x) x = Dropout(0.25, name="base_dropout")(x) x = Conv2D(64, (3, 3), padding='same', activation="relu", name="base_conv2d_3")(x) x = Conv2D(64, (3, 3), padding='same', activation="relu", name="base_conv2d_4")(x) x = MaxPooling2D(pool_size=(2, 2), name="base_maxpooling2d_2")(x) x = Dropout(0.25, name="base_dropout_2")(x) return Model(inputs=in_layer, outputs=x, name="base_model")def create_encoder(): in_layer = Input(shape=(8, 8, 64)) x = Flatten(name="encoder_flatten")(in_layer) x = Dense(512, activation="relu", name="encoder_dense_1")(x) x = Dropout(0.5, name="encoder_dropout_2")(x) x = Dense(10, activation="softmax", name="encoder_dense_2")(x) return Model(inputs=in_layer, outputs=x, name="encoder_model")def extend_base(input_model): x = Flatten(name="custom_flatten")(input_model.output) x = Dense(512, activation="relu", name="custom_dense_1")(x) x = Dropout(0.5, name="custom_dropout_2")(x) x = Dense(10, activation="softmax", name="custom_dense_2")(x) return Model(inputs=input_model.input, outputs=x, name="custom_edit")def connect_layers(from_tensor, to_layer, clear_inbound_nodes=True): try: tmp_output = to_layer.output except AttributeError: raise ValueError("Connecting to shared layers is not supported!") if clear_inbound_nodes: to_layer.inbound_nodes = [] else: tensor_list = to_layer.inbound_nodes[0].input_tensors tensor_list.append(from_tensor) from_tensor = tensor_list to_layer.inbound_nodes = [] new_output = to_layer(from_tensor) for out_node in to_layer.outbound_nodes: for i, in_tensor in enumerate(out_node.input_tensors): if in_tensor == tmp_output: out_node.input_tensors[i] = new_outputif __name__ == "__main__": base = create_base() encoder = create_encoder() #new_model_1 = Model(inputs=base.input, outputs=encoder(base.output)) #plot_model(new_model_1, to_file="plots/new_model_1.png") new_model_2 = extend_base(base) plot_model(new_model_2, to_file="plots/new_model_2.png") print(new_model_2.summary()) base_layer = base.get_layer("base_dropout_2") top_layer = encoder.get_layer("encoder_flatten") connect_layers(base_layer.output, top_layer) new_model_3 = Model(inputs=base.input, outputs=encoder.output) plot_model(new_model_3, to_file="plots/new_model_3.png") print(new_model_3.summary())
我知道这是一大段文字和大量代码。但我觉得有必要解释这里的问题。
编辑: 我刚试了theano,我认为错误信息透露了更多信息:
theano.gradient.DisconnectedInputError: Backtrace when that variable is created:
似乎编码器模型的每一层都通过TensorVariables与编码器输入层有某种连接。
回答: