运行 Keras 中的反向模型

Run model in reverse in Keras

我目前正在研究 Keras 框架。并做了一些简单的分类测试等。我想找到一种方法 运行 网络反向,使用输出作为输入,反之亦然。有什么办法吗?

没有"running a neural net in reverse"这样的东西,因为神经网络的通用架构没有定义任何非前向数据处理。然而,有一个模型子类可以做到——生成模型,现在还不是 keras 的一部分。您唯一可以做的就是创建一个网络,以某种方式 "simulates" 您感兴趣的生成过程。但这是特定模型的特定方法,没有通用的解决方案。

我不确定这个的用例,但只是添加一个快速修复,就是重新设计一个架构,这样输入就被视为输出,反之亦然。

假设您的输入数据的形状(作为示例):

n_obs, n_feat = 1000, 20
n_labels = 2
n_hidden = 100 # you can make this whatever you want

你通常会像这样设计输入层:

Dense(input_dim = n_feat, output_dim = n_hidden)

输出层如:

Dense(input_dim = n_hidden, output_dim = n_labels)

如果您想要 运行 这个 "in reverse",只需制作另一个模型,具有相反的架构,例如:

新输入层:

Dense(input_dim = n_labels, output_dim = n_hidden)

新输出层:

Dense(input_dim = n_hidden, output_dim = n_feat)

但是和上面lejlot说的类似,这里没有单一模型的解决方案。您不能在输入数据上训练模型,然后在输出数据上对其进行测试。这有意义吗?

基础权重矩阵必须具有正确的数据维度,当您尝试为其提供不同形状的数据(即输出数据代替输入数据)时,它无法执行矩阵乘法,即是每个神经网络的核心。

如果您对这一点感到困惑,您应该回顾一下神经网络的实际工作原理。

我认为您正在寻找的是 "Auto-Associative" 神经网络。它有一个 n 维的输入,几个层,其中一个是 m 维的 "middle layer",然后还有几个层导致一个输出层,该输出层的维数与输入层 n.

这里的关键是m远小于n。

它的工作原理是训练网络在输出时重新创建输入。然后你把网络分成两半。前半部分从 n 到 m 维(将输入编码为更小的 space)。后半部分从 m 维到 n 维(解码,或者 "reverse" 如果你愿意)。

对加密、压缩、无监督学习等非常有用

有一种方法,但你的里程可能会有所不同,它可能只是 return 输入的垃圾,尽管 'rubbish' 仍然会产生你开始的输出。关键词是'treat inputs as weights and train them with the rest of the model fixed'.

也就是说,您可以用一层权重替换输入层,冻结模型的其余部分并在固定输出的同时训练这些权重。

为了适应 Keras 的结构,我创建了一个自定义层并将其命名为 'Recover'。在训练模型时不会触发它,但它用作反向训练步骤的人造输入层。 (我确信该方法可以进一步优化,但这是我能想到的最快的方法)。

class Recover(Layer):
    def __init__(self, **kwargs):
        super(Recover, self).__init__(**kwargs)
        self.reverse = False

    def build(self, input_shape):
        self.kernel = self.add_weight(name='kernel', 
                                      shape=(input_shape[1],),
                                      initializer='uniform',
                                      trainable=True)
        super(Recover, self).build(input_shape)

    def call(self, x):
        if self.reverse:
            return K.ones_like(x)*self.kernel
        else:          
            return x

    def compute_output_shape(self, input_shape):
        return (input_shape[0], input_shape[0])

直接在输入层之后添加该层,在该层上设置trainableFalse。首先,正常训练网络,这一层应该被忽略并作为传递。

完成后,重置该层内的权重,将reverse设置为True,将trainable设置为True,将trainable设置为False 对于所有其他层,重新编译模型并重新开始训练。

大致如下:

for x in model.layers:
    x.trainable = False
model.layers[0].trainable = True
model.layers[0].reverse = True
model.compile( ...your compile parameters... )

此时调用 model.fit 时将忽略实际输入,可以只为输入数组指定正确形状的零。

使用这种方法有时会陷入次优解决方案。只需重新初始化 Recover 层的权重并重复。训练完成后,Recover 层的权重可以通过调用 get_weights() 获得,并将对应于原始模型的输入,从而使其产生所需的输出。

结果很可能会像噪声一样,可能需要引入额外的损失(通过在 call 函数中调用 self.add_loss)来强制模型产生有意义的输入。