Skip to main content
 首页 » 编程设计

python之在 tensorflow 双射器中使用和修改变量

2024年12月31日28bluestorm

在引用paper对于 TensorFlow Distributions(现在为 Probability),提到 TensorFlow Variable 可用于构造 Bijector 和 TransformedDistribution 对象,即:

import tensorflow as tf 
import tensorflow_probability as tfp 
tfd = tfp.distributions 
 
tf.enable_eager_execution() 
 
shift = tf.Variable(1., dtype=tf.float32) 
myBij = tfp.bijectors.Affine(shift=shift) 
 
# Normal distribution centered in zero, then shifted to 1 using the bijection 
myDistr = tfd.TransformedDistribution( 
            distribution=tfd.Normal(loc=0., scale=1.), 
            bijector=myBij, 
            name="test") 
 
# 2 samples of a normal centered at 1: 
y = myDistr.sample(2) 
# 2 samples of a normal centered at 0, obtained using inverse transform of myBij: 
x = myBij.inverse(y) 

我现在想修改 shift 变量(比如,我可能会计算一些似然函数的梯度作为 shift 的函数并更新它的值)所以我这样做

shift.assign(2.) 
gx = myBij.forward(x) 

我希望 gx=y+1,但我看到 gx=y... 事实上,myBij.shift仍然评估为 1。

如果我尝试直接修改双射器,即:

myBij.shift.assign(2.) 

我明白了

AttributeError: 'tensorflow.python.framework.ops.EagerTensor' object has no attribute 'assign' 

计算梯度也没有按预期工作:

with tf.GradientTape() as tape: 
    gx = myBij.forward(x) 
grad = tape.gradient(gx, shift) 

产生 None,以及脚本结束时的异常:

Exception ignored in: <bound method GradientTape.__del__ of <tensorflow.python.eager.backprop.GradientTape object at 0x7f529c4702e8>> 
Traceback (most recent call last): 
File "~/.local/lib/python3.6/site-packages/tensorflow/python/eager/backprop.py", line 765, in __del__ 
AttributeError: 'NoneType' object has no attribute 'context' 

我在这里错过了什么?

编辑:我让它与图形/ session 一起工作,所以似乎急切执行存在问题......

注意:我有tensorflow 1.12.0版和tensorflow_probability 0.5.0版

请您参考如下方法:

如果您使用的是 eager 模式,则需要重新计算从变量 forward 开始的所有内容。最好在函数中捕获此逻辑;

import tensorflow as tf 
import tensorflow_probability as tfp 
tfd = tfp.distributions 
 
tf.enable_eager_execution() 
 
shift = tf.Variable(1., dtype=tf.float32) 
def f(): 
  myBij = tfp.bijectors.Affine(shift=shift) 
 
  # Normal distribution centered in zero, then shifted to 1 using the bijection 
  myDistr = tfd.TransformedDistribution( 
            distribution=tfd.Normal(loc=0., scale=1.), 
            bijector=myBij, 
            name="test") 
 
  # 2 samples of a normal centered at 1: 
  y = myDistr.sample(2) 
  # 2 samples of a normal centered at 0, obtained using inverse 
  # transform of myBij: 
  x = myBij.inverse(y) 
  return x, y 
x, y = f() 
shift.assign(2.) 
gx, _ = f() 

关于渐变,您需要将对 f() 的调用包装在 GradientTape

中