machine-learning - Keras:连接不同模型的两层以创建新模型

标签 machine-learning deep-learning keras concatenation models

我正在尝试做的事情:
我想连接不同模型中的任何层来创建一个新的 keras 模型。

到目前为止我发现了什么:
https://github.com/keras-team/keras/issues/4205 :使用模型的调用类来更改另一个模型的输入。我对这种方法的问题:

  • 只能改变Model的输入,不能改变其他层。所以如果我想在编码器的开头切断一些层,这是不可能的
  • 在获取配置文件时不喜欢嵌套数组结构。更喜欢一维数组
  • 当使用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 :使用基础模型的任何输出向基础模型添加新层。这里的问题:

  1. 虽然可以使用基本模型中的任何层,这意味着我可以从基本模型中切断层,但我无法将编码器作为 keras 模型加载。顶级模型必须始终是新的。

我尝试过的:
我连接不同模型的任何层的方法:

  1. 清除输入层的入站节点
  2. 使用输出层的call()方法和输出层的张量
  3. 通过将新创建的张量与之前的输出张量交换来清理输出张量的出站节点

一开始我真的很乐观,因为 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 作为后端。我能够追溯到这个错误的根源。看起来梯度计算时有错误。通常,每个节点都有一个梯度计算,但是当使用我的方法时,基础网络的所有节点都是“无”。所以基本上在 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_output


if __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())

我知道这是很多文本和代码。但我觉得有必要在这里解释一下这个问题。

编辑:我刚刚尝试过 thenao,我认为该错误泄露了更多信息:

theano.gradient.DisconnectedInputError:  
Backtrace when that variable is created:

编码器模型的每一层似乎都通过 TensorVariables 与编码器输入层有某种联系。

最佳答案

这就是我最终得到的 connect_layer() 函数:

def connect_layers(from_tensor, to_layer, old_tensor=None):
    # if there is any shared layer after the to_layer, it is not supported
    try:
        tmp_output = to_layer.output
    except AttributeError:
        raise ValueError("Connecting to shared layers is not supported!")
    # check if to_layer has multiple input_tensors, and therefore some sort of merge layer
    if len(to_layer.inbound_nodes[0].input_tensors) > 1:
        tensor_list = to_layer.inbound_nodes[0].input_tensors
        found_tensor = False
        for i, tensor in enumerate(tensor_list):
            # exchange the old tensor with the new created tensor
            if tensor == old_tensor:
                tensor_list[i] = from_tensor
                found_tensor = True
                break
        if not found_tensor:
            tensor_list.append(from_tensor)
        from_tensor = tensor_list
        to_layer.inbound_nodes = []
    else:
        to_layer.inbound_nodes = []

    new_output = to_layer(from_tensor)

    tmp_out_nodes = to_layer.outbound_nodes[:]
    to_layer.outbound_nodes = []
    # recursively connect all layers after the current to_layer 
    for out_node in tmp_out_nodes:
        l = out_node.outbound_layer
        print("Connecting: " + str(to_layer) + " ----> " + str(l))
        connect_layers(new_output, l, tmp_output)

由于每个张量都通过 ->owner.inputs ->owner.inputs -> ... 拥有有关其根张量的所有信息,因此必须更新 new_output 张量之后的所有张量。
使用 theano 进行调试比使用 Tensorflow 后端要容易得多。

我仍然需要弄清楚如何处理共享层。在当前实现中,无法连接第一个 to_layer 之后包含共享层的其他模型。

关于machine-learning - Keras:连接不同模型的两层以创建新模型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47924706/

相关文章:

matlab - GMModel - 如何使用它来预测标签的数据?

python - 如何将 Pandas DataFrame 转换为 Pandas ML ModelFrame?

python - 如何使用 keras 保存最佳权重和最佳模型

python - 如何用keras显示多张图像?

python-3.x - keras 与tensorflow.keras

python - Keras - 将 3 channel 图像输入 LSTM

machine-learning - Tensorflow 中的加性高斯噪声

algorithm - Apache Spark Mllib 中 ALS 机器学习算法的排名是多少

python-3.x - 'EarlyStopping' 对象没有属性 'on_train_batch_begin'

image - 如何检测图像中的裂缝?