【问题标题】:Tensorflow probability - Bijector trainingTensorFlow 概率 - Bijector 训练
【发布时间】:2020-08-06 15:12:12
【问题描述】:

我一直在尝试遵循 tutorial 中的示例,但我无法训练任何变量。

我写了一个小例子,但我也没能成功:

# Train a shift bijector
shift = tf.Variable(initial_value=tf.convert_to_tensor([1.0], dtype=tf.float32), trainable=True, name='shift_var')
bijector = tfp.bijectors.Shift(shift=shift)

# Input
x = tf.convert_to_tensor(np.array([0]), dtype=tf.float32)
target = tf.convert_to_tensor(np.array([2]), dtype=tf.float32)

optimizer = tf.optimizers.Adam(learning_rate=0.5)
nsteps = 1

print(bijector(x).numpy(), bijector.shift)
for _ in range(nsteps):

    with tf.GradientTape() as tape:
        out = bijector(x)
        loss = tf.math.square(tf.math.abs(out - target))
        #print(out, loss)
    
        gradients = tape.gradient(loss, bijector.trainable_variables)
    
    optimizer.apply_gradients(zip(gradients, bijector.trainable_variables))
    
print(bijector(x).numpy(), bijector.shift)

对于 nsteps = 1,两个打印语句产生以下输出:

[1.] <tf.Variable 'shift_var:0' shape=(1,) dtype=float32, numpy=array([1.], dtype=float32)>
[1.] <tf.Variable 'shift_var:0' shape=(1,) dtype=float32, numpy=array([1.4999993], dtype=float32)>

看起来bijector 仍然使用原始的shift,即使bijector.shift 的打印值已经更新。

我无法增加nsteps,因为第一次迭代后梯度为None,我得到了这个错误:

ValueError: No gradients provided for any variable: ['shift_var:0'].

我正在使用

tensorflow version 2.3.0
tensorflow-probability version 0.11.0

我也在colab notebook上试过,所以怀疑是版本问题。

【问题讨论】:

    标签: python tensorflow tensorflow-probability


    【解决方案1】:

    你发现了一个错误。双射器前向函数弱缓存结果->输入映射以使下游逆和对数行列式快速。但不知何故,这也干扰了梯度。一种解决方法是添加del out,如https://colab.research.google.com/gist/brianwa84/04249c2e9eb089c2d748d05ee2c32762/bijector-cache-bug.ipynb

    【讨论】:

      【解决方案2】:

      仍然不确定我是否完全理解这里发生了什么,但至少我现在可以让我的示例正常工作。

      由于某种原因,如果我将其包装在从 tf.keras.Model 继承的类中,则行为会有所不同:

      class BijectorModel(tf.keras.Model):
      
          def __init__(self):
              super().__init__()
      
              self.shift = tf.Variable(initial_value=tf.convert_to_tensor([1.5], dtype=tf.float32), trainable=True, name='shift_var')
              self.bijector = tfp.bijectors.Shift(shift=self.shift)
      
          def call(self, input):
              return self.bijector(input)
      
      

      我为训练迭代制作了一个函数,虽然这似乎没有必要:

      def training_iteration(model, input, target):
      
          optimizer = tf.optimizers.SGD(learning_rate=0.1)
      
          with tf.GradientTape() as tape:
      
              loss = tf.math.square(tf.math.abs(model(input) - target))
      
              gradients = tape.gradient(loss, model.trainable_variables)
      
          optimizer.apply_gradients(zip(gradients, model.trainable_variables))
      
      

      这样执行

      x = tf.convert_to_tensor(np.array([0]), dtype=tf.float32)
      target = tf.convert_to_tensor(np.array([2]), dtype=tf.float32)
      model = BijectorModel()
      
      nsteps = 10
      for _ in range(nsteps):
          training_iteration(model, x, target)
          print('Iteration {}: Output {}'.format(_, model(x)))
      

      产生期望/期望的输出:

      Iteration 0: Output [1.6]
      Iteration 1: Output [1.6800001]
      Iteration 2: Output [1.7440001]
      Iteration 3: Output [1.7952001]
      Iteration 4: Output [1.8361601]
      Iteration 5: Output [1.8689281]
      Iteration 6: Output [1.8951424]
      Iteration 7: Output [1.916114]
      Iteration 8: Output [1.9328911]
      Iteration 9: Output [1.9463129]
      

      我的结论是,与通过双射器对象访问相比,可训练变量在模型中的处理方式不同。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-04-15
        • 2016-03-09
        • 2020-08-05
        • 1970-01-01
        • 1970-01-01
        • 2017-03-30
        • 2017-08-21
        相关资源
        最近更新 更多