【问题标题】:How to pass epoch-dependent parameters to a custom layer in Keras如何将时代相关参数传递给 Keras 中的自定义层
【发布时间】:2018-06-29 12:22:27
【问题描述】:

我正在尝试在 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)

在训练过程中,如何将当前epoch的稀疏度传递给KSparse

【问题讨论】:

  • 我正在处理同样的问题,我在this Github issue 上发现了一个类似的问题。回复者建议使用每个纪元更新的纪元计数器添加不可训练的权重。我仍在寻找如何实现它。如果我能够使其工作,将在此处发布答案

标签: python tensorflow keras


【解决方案1】:

您无法动态更改图层属性,因为计算图是在生成时基于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
  # ...

【讨论】:

  • 感谢您的回复!我懂了。您能否详细说明我如何使用这个额外的Input 层将纪元的稀疏级别动态传递给KSparse
  • 您只需传递一个输入列表,包括您可以在调用方法中单独使用的稀疏级别,我添加了更多代码来帮助解决这个问题。我假设您使用的是functional API
  • 我正在使用函数式 API。我已经了解了您在编辑中包含的内容,但是我仍然看不到如何通过使用训练纪元号切片 sparsity_level_per_epoch 来为 sparsity_level 分配不同的值。您能否提供一些有关如何/在何处完成的代码?
  • 这就像传递任何其他数据一样,对于每个数据点,您现在将给出一个先验计算的稀疏度级别并作为输入传递。这一切都发生在 Keras 外部的 NumPy 中。您可能必须为每个数据点重复每个时期的稀疏度级别,以便为每个数据点设置稀疏度级别。
猜你喜欢
  • 2021-08-18
  • 1970-01-01
  • 1970-01-01
  • 2015-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-15
  • 1970-01-01
相关资源
最近更新 更多