繁体   English   中英

如何在不使用 Sequential() 的情况下堆叠 Keras 中的图层?

[英]How to stack layers in Keras without using Sequential()?

如果我有一个 keras 层 L,并且我想在 keras model 中堆叠该层的 N 个版本(具有不同的权重),那么最好的方法是什么? 请注意,这里的 N 很大并且由超参数控制。 如果 N 很小,那么这不是问题(我们可以手动重复一行 N 次)。 因此,让我们假设 N > 10。

如果图层只有一个输入和一个 output,我可以这样做:

m = Sequential()
for i in range(N):
    m.add(L)

但如果我的层实际上需要多个输入,这就不起作用了。 例如,如果我的图层具有 z = L(x, y) 的形式,并且我希望我的 model 执行以下操作:

x_1 = L(x_0, y)
x_2 = L(x_1, y)
...
x_N = L(x_N-1, y)

那么 Sequential 将无法完成这项工作。 我想我可以子类化 keras model,但我不知道将 N 层放入 class 的最干净的方法是什么。我可以使用一个列表,例如:

class MyModel(Model):
    def __init__(self):
        super(MyModel, self).__init__()
        self.layers = []
        for i in range(N):
            self.layers.append(L)
    def call(self, inputs):
        x = inputs[0]
        y = inputs[1]
        for i in range(N):
            x = self.layers[i](x, y)
        return x

但这并不理想,因为 keras 不会识别这些层(它似乎没有将层列表视为“checkpointables”)。 例如,MyModel.variables 将为空,而 MyModel.Save() 不会保存任何内容。

我还尝试使用功能性 API 定义 model,但它在我的情况下也不起作用。 事实上,如果我们这样做

def MyModel():
    input = Input(shape=...)
    output = SomeLayer(input)
    return Model(inputs=input, outputs=output)

如果 SomeLayer 本身是自定义的 model(它会引发 NotImplementedError),它将不会运行。

有什么建议么?

不确定我的问题是否正确,但我想您可以使用功能API并concatenateadd Keras应用程序中的图层,如ResNet50InceptionV3,以构建“非顺序”网络。

UPDATE

在我的一个项目中,我使用的是这样的东西。 我有一个自定义图层(它没有在我的Keras版本中实现,所以我只是手动将代码“后移”到我的笔记本中)。

class LeakyReLU(Layer):
    """Leaky version of a Rectified Linear Unit backported from newer Keras 
    version."""

    def __init__(self, alpha=0.3, **kwargs):
        super(LeakyReLU, self).__init__(**kwargs)
        self.supports_masking = True
        self.alpha = K.cast_to_floatx(alpha)

    def call(self, inputs):
        return tf.maximum(self.alpha * inputs, inputs)

    def get_config(self):
        config = {'alpha': float(self.alpha)}
        base_config = super(LeakyReLU, self).get_config()
        return dict(list(base_config.items()) + list(config.items()))

    def compute_output_shape(self, input_shape):
        return input_shape

然后,模型:

def create_model(input_shape, output_size, alpha=0.05, reg=0.001):
    inputs = Input(shape=input_shape)

    x = Conv2D(16, (3, 3), padding='valid', strides=(1, 1), 
               kernel_regularizer=l2(reg), kernel_constraint=maxnorm(3),
               activation=None)(inputs)
    x = BatchNormalization()(x)
    x = LeakyReLU(alpha=alpha)(x)
    x = MaxPooling2D(pool_size=(2, 2))(x)

    x = Conv2D(32, (3, 3), padding='valid', strides=(1, 1),
               kernel_regularizer=l2(reg), kernel_constraint=maxnorm(3),
               activation=None)(x)
    x = BatchNormalization()(x)
    x = LeakyReLU(alpha=alpha)(x)
    x = MaxPooling2D(pool_size=(2, 2))(x)

    x = Conv2D(64, (3, 3), padding='valid', strides=(1, 1),
               kernel_regularizer=l2(reg), kernel_constraint=maxnorm(3),
               activation=None)(x)
    x = BatchNormalization()(x)
    x = LeakyReLU(alpha=alpha)(x)
    x = MaxPooling2D(pool_size=(2, 2))(x)

    x = Conv2D(128, (3, 3), padding='valid', strides=(1, 1),
               kernel_regularizer=l2(reg), kernel_constraint=maxnorm(3),
               activation=None)(x)
    x = BatchNormalization()(x)
    x = LeakyReLU(alpha=alpha)(x)
    x = MaxPooling2D(pool_size=(2, 2))(x)

    x = Conv2D(256, (3, 3), padding='valid', strides=(1, 1),
               kernel_regularizer=l2(reg), kernel_constraint=maxnorm(3),
               activation=None)(x)
    x = BatchNormalization()(x)
    x = LeakyReLU(alpha=alpha)(x)
    x = MaxPooling2D(pool_size=(2, 2))(x)

    x = Flatten()(x)
    x = Dense(500, activation='relu', kernel_regularizer=l2(reg))(x)
    x = Dense(500, activation='relu', kernel_regularizer=l2(reg))(x)
    x = Dense(500, activation='relu', kernel_regularizer=l2(reg))(x)
    x = Dense(500, activation='relu', kernel_regularizer=l2(reg))(x)
    x = Dense(500, activation='relu', kernel_regularizer=l2(reg))(x)
    x = Dense(500, activation='relu', kernel_regularizer=l2(reg))(x)
    x = Dense(output_size, activation='linear', kernel_regularizer=l2(reg))(x)

    model = Model(inputs=inputs, outputs=x)

    return model

最后,一个自定义指标:

def root_mean_squared_error(y_true, y_pred):
    return K.sqrt(K.mean(K.square(y_pred - y_true), axis=-1))

我使用以下代码片段来创建和编译模型:

model = create_model(input_shape=X.shape[1:], output_size=y.shape[1])
model.compile(loss=root_mean_squared_error, optimizer='adamax')

像往常一样,我使用检查点回调来保存模型。 要加载模型,您还需要将自定义图层类和指标传递给load_model函数:

def load_custom_model(path):
    return load_model(path, custom_objects={
        'LeakyReLU': LeakyReLU,
        'root_mean_squared_error': root_mean_squared_error
    })

有帮助吗?

在对此进行了大量研究之后:我确信在 Tensorflow/Keras 中没有内置的通用方法来执行此操作。

然而,仍然有一些方法可以以不同的方式实现相同的目标。 问题是在 Tensorflow 和任何 Keras 层中没有通用的解决方案,所以你必须根据具体情况来处理它。

因此,例如,如果您想要做的是堆叠一堆Dense层,然后让输入的某个维度对应于每个层(简单示例),那么您想要做的是构建一个自定义Dense层和为其权重和偏差添加额外的维度,然后在给定输入中的一些额外维度的情况下执行适当的操作。

所以最终相同的(期望的)操作将按照你希望的方式在这里执行,每个维度上的每个输入都将通过一个单独的Dense层,具有单独的权重/偏差:但它会同时完成,没有任何python 循环。 本质上,您将减少图形的大小和复杂性,并以更并发的方式执行相同的操作; 这应该更有效率。

此处概述的策略适用于任何层/输入类型。 这不是什么好消息,因为如果有一些标准化的 Keras 友好方式来堆叠一堆层,然后以一种不涉及python 循环,而是将内部参数连接到一个新维度,并在输入和参数的额外“堆叠”维度之间管理 alignment。

就像,以同样的方式我们有tf.keras.Sequential我们也可以从tf.keras.Parallel类的东西中受益,作为这种常见 ML 需求的通用解决方案。

如果我正确理解您的问题,您只需在构建模型时使用for循环即可解决此问题。 我不确定你是否需要任何特殊的层,所以我假设你只在这里使用Dense:

def MyModel():
    input = Input(shape=...)
    x = input
    for i in range(N):
        x = Dense(number_of_nodes, name='dense %i' %i)(x)
        // Or some custom layers
    output = Dense(number_of_output)(x)

    return Model(inputs=input, outputs=output)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM