TensorFlow:将Keras与可学习的tfp.bijectors / tfp.distributions结合使用

时间:2018-10-28 22:47:37

标签: python tensorflow keras reinforcement-learning tensorflow-probability

我正在尝试使用tf.keras重构一些强化学习方法。对于我用于值函数和预处理器的前馈网络,keras模型似乎工作得很好,但是在尝试使用keras实现某些概率模型(例如策略)时,我很费劲。特别是,将tfp.distributions和tfp.bijector与tf.keras.Model结合使用对我来说非常不直观,我所看到的所有示例(例如[1、2、3])都过于简单或依赖在我看来,“骇客”似乎破坏了使用keras模型的许多好处(例如,从模型本身隐藏输入处理,会话和数字评估的能力)。

假设我要实现一个潜在空间策略,如[4]中所述,该策略使用RealNVP流将以状态为条件的高斯样本转换为动作。该策略需要支持至少两个操作: 1.对动作Y进行采样,使得     Y = g(X | S)     X〜普通(0,1),    其中g是[4,5]中描述的RealNVP转换,而S是条件变量(例如RL情况下的状态观察)。 2.计算采样的Y的对数概率。

一个简单的实现可能看起来像这样:

class LearnableConditionalRealNVP(object):
    def __init__(self, input_shape, output_shape):
        self._input_shape = input_shape
        self._output_size = np.prod(output_shape)

        conditions = tf.keras.layers.Input(shape=input_shape)

        batch_size = tf.keras.layers.Lambda(
            lambda x: tf.shape(x)[0])(conditions)

        def samples_and_log_probs_fn(inputs):
            conditions, batch_size = inputs

            base_distribution = tfp.distributions.MultivariateNormalDiag(
                loc=tf.zeros(output_shape),
                scale_diag=tf.ones(output_shape))

            real_nvp_bijector = tfp.bijectors.RealNVP(
                num_masked=self._output_size // 2,
                shift_and_log_scale_fn=conditioned_real_nvp_template(
                    hidden_layers=(128, 128),
                    activation=tf.nn.relu),
                name='real_nvp')

            distribution = (
                tfp.distributions.ConditionalTransformedDistribution(
                    distribution=base_distribution,
                    bijector=real_nvp_bijector))

            samples = distribution.sample(batch_size)
            log_probs = distribution.log_prob(samples)

            return [samples, tf.reshape(log_probs, (-1, 1))]

        samples, log_probs = tf.keras.layers.Lambda(
            samples_and_log_probs_fn)([conditions, batch_size])

        self.samples_and_log_probs_model = tf.keras.Model(
            conditions, [samples, log_probs])

    def samples_and_log_probs(self, conditions):
        return self.samples_and_log_probs_model(conditions)

    def samples_and_log_probs_np(self, conditions):
        return self.samples_and_log_probs_model.predict(conditions)

其中conditioned_real_nvp_template创建一个前馈网络,该网络沿最后一个轴连接潜在样本和条件值,并将它们用作输入。完整的示例可以在这里找到:https://gist.github.com/hartikainen/17ac2ec102032e986cb4d31e225f592a

这种处理发行方式对我有两个主要好处。首先,我不必手动处理参数的重用。我可以在代码中多次调用samples_and_log_probs,它会自动重用模型的参数。其次,如果我想获得数字输出,则无需了解会话。将中间层包装到自己的模型中,使我可以调用用于处理会话的预测方法。

在进一步扩展示例时会出现问题。假设我想修改LearnableConditionalRealNVP,以便可以提供潜在样本x作为输入,而不是在distribution.sample()中调用samples_and_log_probs_fn,它将返回{{1} }。或者,也许我想将样本和log_probs从模型中分离出来。这将需要我将distribution.forward(x)拆分为两个单独的lambda函数,但是如果我想共享RealNVP双射器的参数,这样做并不是一件容易的事(因为我无法将双射器作为输入/输出传递给/来自keras层。

我尝试通过将samples_and_log_probs_fn的{​​{1}}子类化来解决这些问题,但是我的所有尝试都导致实现混乱,主要是由于输入和输出的变化。具体来说,我无法为模型创建LearnableConditionalRealNVP方法,以至于该模型将保留与tf.keras.Model一起使用的功能,因此我不得不在{{1 }}-方法。这些都不让人感到可怕,但是它们确实增加了使用keras模型的开销,以至于我可以更轻松地在普通的tensorflow中实现这些类型的事情,并手动处理会话,numpy输出等。

我的问题是:

  1. 张量流双射/分布是否应该与keras(模型)兼容?如果是的话,有人知道我是否可以找到一些非平凡的例子?如果它们不兼容,是否有计划使其兼容?
  2. 在我认为一个模型具有多个不同输出的情况下,应如何使用keras模型?例如,在上面的示例中,可学习的RealNVP分布直观地感觉应该是一个模型,但是它具有多个(可能是独立的)输入/输出,这使其很难适应keras模型框架。我愿意接受我的理解是错误的,在这种情况下,很高兴听到构建这种模型的最佳实践是什么。
  3. 是否有一种方法可以像[1]中那样将非张量数据作为输入输出传递到keras模型或从keras模型传递出来,同时仍然保持模型之间的连接。如果在此示例中使用输入而不是call,则会中断,因为图形未连接。

编辑:发布此内容并使用上述实现进行一些其他测试后,我注意到该模型毕竟是不可训练的,因为RealNVP bijector的变量是在keras lambda层中创建的。这表明我完全不能将构建这些模型的功能方法用于这些类型的模型。

[1] https://github.com/tensorflow/probability/blob/5f5510201865350b6cce2a0f18fbe0cdf4f15eee/tensorflow_probability/examples/disentangled_vae.py#L186

[2] https://blog.keras.io/building-autoencoders-in-keras.html

[3] http://louistiao.me/posts/implementing-variational-autoencoders-in-keras-beyond-the-quickstart-tutorial/

[4] https://arxiv.org/pdf/1804.02808.pdf

[5] https://arxiv.org/abs/1605.08803

0 个答案:

没有答案