如何将历时相关的参数传递给Keras中的自定义层

时间:2018-06-29 12:22:28

标签: python tensorflow keras

我正在尝试在Keras中实现k-sparse autoencoder(以Tensorflow为后端)。原始论文的作者建议在训练过程中应逐渐增加中间层的稀疏性:

  

假设我们的目标稀疏度为k = 15。   然后,我们从大范围的稀疏性开始(例如   k = 100),k稀疏自动编码器可以对其进行训练   所有隐藏的单位。然后,我们线性减小   最初的稀疏度从k = 100到k = 15   一半的时代。这会在   一个好的政权,所有隐藏的单位都有   被拣选的机会很大。然后,我们继续   对于后半段,k = 15。有了这个   调度,我们可以训练所有过滤器,即使对于   稀疏级别。

我的自定义图层如下所示,并且在所有时期均适用于静态稀疏级别k

from keras.layers import Layer
from keras import backend as K

class KSparse(Layer):
    def __init__(self, k=15, **kwargs):
        self.k = k
        self.uses_learning_phase = True
        super().__init__(**kwargs)

    def call(self, inputs):
        return K.in_train_phase(self.k_sparsify(inputs), inputs)

    def k_sparsify(self, inputs):
        k = self.k
        kth_smallest = K.tf.contrib.framework.sort(inputs)[..., K.shape(inputs)[-1]-1-k]
        return inputs * K.cast(K.greater(inputs, kth_smallest[:, None]), K.floatx())

    def compute_output_shape(self, input_shape):
        return input_shape

我每个时期都有一个所需的稀疏性级别数组,并且有一个访问当前时期的回调:

import numpy as np
from keras.callbacks import LambdaCallback

def sparsity_level_per_epoch(n_epochs):
    return np.hstack((np.linspace(100, 15, n_epochs // 2, dtype=np.int),
                      np.repeat(15, n_epochs // 2)))


nth_epoch = LambdaCallback(on_epoch_begin=lambda epoch, logs: epoch)

在训练期间,如何将当前纪元的稀疏度传递给KSparse

1 个答案:

答案 0 :(得分:0)

您无法动态更改图层属性,因为计算图是在生成时基于k静态生成的。换句话说,k_sparsify应用于固定的kcall方法实际上被调用一次。如果您有一个外部更改参数,则一种选择是使其成为输入:

sparsity_level = Input(shape=(...))
# ...
out = KSparse()([x, sparsity_level])

并将sparsity_level张量传递到KSparse层,因此该值现在取决于张量而不是类属性。您可以像已经做过的那样,在训练之前脱机计算这些级别并立即作为输入传递。

# inside KSparse you get a list of inputs
def call(self, inputs):
  x, sparsity_level = inputs # the things we pass in
  # ...