我正在尝试在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
?
答案 0 :(得分:0)
您无法动态更改图层属性,因为计算图是在生成时基于k
静态生成的。换句话说,k_sparsify
应用于固定的k
,call
方法实际上被调用一次。如果您有一个外部更改参数,则一种选择是使其成为输入:
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
# ...