如果我有一个keras层L,并且想在keras模型中堆叠该层的N个版本(具有不同的权重),那么最好的方法是什么?请注意,此处N很大,并且受超参数控制。如果N小,那么这不是问题(我们可以手动重复一行N次)。因此,我们假设N> 10。
如果该图层只有一个输入和一个输出,则可以执行以下操作:
m = Sequential()
for i in range(N):
m.add(L)
但是,如果我的图层实际接受多个输入,则此操作将无效。例如,如果我的图层的形式为z = L(x,y),并且我希望我的模型可以这样做:
x_1 = L(x_0, y)
x_2 = L(x_1, y)
...
x_N = L(x_N-1, y)
然后,Sequential无法完成这项工作。我认为我可以对keras模型进行子类化,但是我不知道将N层放入类中的最干净方法是什么。我可以使用一个列表,例如:
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定义模型,但在我的情况下也无法使用。实际上,如果我们这样做
def MyModel():
input = Input(shape=...)
output = SomeLayer(input)
return Model(inputs=input, outputs=output)
如果SomeLayer本身是自定义模型,它将无法运行(它会引发NotImplementedError)。
有什么建议吗?
答案 0 :(得分:3)
不确定我的问题是否正确,但我想您可以使用功能性API和concatenate
或add
层,如Keras应用程序中所示,例如{{3 }}或ResNet50建立“非顺序”网络。
更新
在我的一个项目中,我正在使用类似的东西。我有一个自定义层(在我的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
})
有帮助吗?
答案 1 :(得分:0)
如果我正确理解了您的问题,则可以在构建模型时简单地通过使用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)