Переменные в пользовательском дистрибутиве на уровне LAMBDA не обновляются

#python #keras #tensorflow-probability #densevariational

Вопрос:

Я хотел бы создать пользовательский слой, tensorflow-probability который я затем могу использовать для создания задней части DenseVariational слоя.

В качестве первого шага я построил следующий апостериор, который эквивалентен апостериору среднего поля, используемому в этом учебнике, но вместо изучения параметров нормального распределения изучаются параметры двух биекторов.

 def posterior_trainable_bijector(kernel_size, bias_size=0, dtype=None):
    n = kernel_size   bias_size
    c = np.log(np.expm1(1.0))

    return tf.keras.Sequential(
        [
            tfp.layers.VariableLayer(2 * n, dtype=dtype),
            tfp.layers.DistributionLambda(
                lambda t: tfp.distributions.TransformedDistribution(
                    tfd.Independent(
                        tfd.Normal(loc=tf.zeros(n), scale=tf.ones(n)),
                        reinterpreted_batch_ndims=1,
                    ),
                    tfp.bijectors.Chain(
                        bijectors=[
                            tfp.bijectors.Shift(t[..., n:]),
                            tfp.bijectors.Scale(
                                1e-5   0.01 * tf.math.softplus(c   t[..., :n])
                            ),
                        ]
                    ),
                )
            ),
        ]
    )

 

В качестве следующего шага я подумал, что было бы неплохо подклассировать DistributionLambda слой, потому что это позволило бы создать более сложные биекторы.
К сожалению, мой первый набросок, похоже, не работает. Чтобы быть более конкретным, я все еще могу запускать свой код, но он выглядит так, как будто loc_params / scale_params не обновляется во время обучения, но я не мог понять, почему это так.
Есть какие-нибудь предложения?

 class LocScaleBijectorLayer(tfp.layers.DistributionLambda):
    def __init__(
        self,
        event_shape=(),
        convert_to_tensor_fn=tfd.Distribution.sample,
        validate_args=False,
        name="LocScaleBijectorLayer",
        **kwargs,
    ):

        c = np.log(np.expm1(1.0))
        with tf.name_scope(name) as name:
            loc_params = tf.Variable(
                tf.zeros(event_shape), name="loc_var", trainable=True
            )
            scale_params = tf.Variable(
                tf.ones(event_shape), name="scale_var", trainable=True
            )

            self.base_distribution = tfd.Independent(
                tfd.Normal(loc=tf.zeros(event_shape), scale=tf.ones(event_shape)),
                reinterpreted_batch_ndims=-1,
            )

            self.bijector = tfp.bijectors.Chain(
                bijectors=[
                    tfp.bijectors.Shift(loc_params),
                    tfp.bijectors.Scale(
                        1e-5   0.01 * tf.math.softplus(c   scale_params)
                    ),
                ]
            )

            super(LocScaleBijectorLayer, self).__init__(
                lambda t: tfp.distributions.TransformedDistribution(
                    self.base_distribution, self.bijector
                ),
                convert_to_tensor_fn,
                name=name,
                **kwargs,
            )
 

Комментарии:

1. График тензорного потока, по-видимому, нарушен в реализации слоя LocScaleBijectorLayer, так как параметр make_distribution_fn (или лямбда-выражение t: tfp.distributions. TransformedDistribution() в вашем случае) должен принимать выходные данные предыдущего слоя. Тем не менее, вы вообще не используете этот параметр лямбда «t» в реализации, поэтому оптимизация за счет обратного распространения не зависит от входных данных, которые приводят к неучтенным параметрам.