实现Wang与Blei的Deconfounder时遇Tensor损失需tape的ValueError求助
问题:Deconfounder实现中TensorFlow优化器报错处理
我正在实现Wang和Blei提出的Deconfounder,执行代码行train = optimizer.minimize(-elbo,var_list=[qb, qw, qw2, qz])时触发错误:
ValueError:
tapeis required when aTensorloss is passed. Received: loss=1950770.5, tape=None
不确定minimize()的var_list参数是否正确,尝试用tf.GradientTape()也没解决,求帮助。
相关代码如下:
def variational_model(qb_mean, qb_stddv, qw_mean, qw_stddv, qw2_mean, qw2_stddv, qz_mean, qz_stddv): qb = ed.Normal(loc=qb_mean, scale=qb_stddv, name="qb") qw = ed.Normal(loc=qw_mean, scale=qw_stddv, name="qw") qw2 = ed.Normal(loc=qw2_mean, scale=qw2_stddv, name="qw2") qz = ed.Normal(loc=qz_mean, scale=qz_stddv, name="qz") return qb, qw, qw2, qz log_q = ed.make_log_joint_fn(variational_model) def target(b, w, w2, z): """Unnormalized target density as a function of the parameters.""" return log_joint(data_dim=data_dim, latent_dim=latent_dim, num_datapoints=num_datapoints, stddv_datapoints=stddv_datapoints, mask=1-holdout_mask, w=w, z=z, w2=w2, b=b, x=x_train) def target_q(qb, qw, qw2, qz): return log_q(qb_mean=qb_mean, qb_stddv=qb_stddv, qw_mean=qw_mean, qw_stddv=qw_stddv, qw2_mean=qw2_mean, qw2_stddv=qw2_stddv, qz_mean=qz_mean, qz_stddv=qz_stddv, qw=qw, qz=qz, qw2=qw2, qb=qb) qb_mean = tf.Variable(np.ones([1, data_dim]), dtype=tf.float32) qw_mean = tf.Variable(np.ones([latent_dim, data_dim]), dtype=tf.float32) qw2_mean = tf.Variable(np.ones([latent_dim, data_dim]), dtype=tf.float32) qz_mean = tf.Variable(np.ones([num_datapoints, latent_dim]), dtype=tf.float32) qb_stddv = tf.nn.softplus(tf.Variable(0 * np.ones([1, data_dim]), dtype=tf.float32)) qw_stddv = tf.nn.softplus(tf.Variable(-4 * np.ones([latent_dim, data_dim]), dtype=tf.float32)) qw2_stddv = tf.nn.softplus(tf.Variable(-4 * np.ones([latent_dim, data_dim]), dtype=tf.float32)) qz_stddv = tf.nn.softplus(tf.Variable(-4 * np.ones([num_datapoints, latent_dim]), dtype=tf.float32)) qb, qw, qw2, qz = variational_model(qb_mean=qb_mean, qb_stddv=qb_stddv, qw_mean=qw_mean, qw_stddv=qw_stddv, qw2_mean=qw2_mean, qw2_stddv=qw2_stddv, qz_mean=qz_mean, qz_stddv=qz_stddv) energy = target(qb, qw, qw2, qz) entropy = -target_q(qb, qw, qw2, qz) elbo = energy + entropy optimizer = tf.optimizers.Adam(learning_rate = 0.05) train = optimizer.minimize(-elbo,var_list=[qb, qw, qw2, qz]) init = tf.global_variables_initializer() t = [] num_epochs = 500 with tf.Session() as sess: sess.run(init) for i in range(num_epochs): sess.run(train) if i % 5 == 0: t.append(sess.run([elbo])) b_mean_inferred = sess.run(qb_mean) b_stddv_inferred = sess.run(qb_stddv) w_mean_inferred = sess.run(qw_mean) w_stddv_inferred = sess.run(qw_stddv) w2_mean_inferred = sess.run(qw2_mean) w2_stddv_inferred = sess.run(qw2_stddv) z_mean_inferred = sess.run(qz_mean) z_stddv_inferred = sess.run(qz_stddv) print("Inferred axes:") print(w_mean_inferred) print("Standard Deviation:") print(w_stddv_inferred) plt.plot(range(1, num_epochs, 5), t) plt.show() def replace_latents(b, w, w2, z): def interceptor(rv_constructor, *rv_args, **rv_kwargs): """Replaces the priors with actual values to generate samples from.""" name = rv_kwargs.pop("name") if name == "b": rv_kwargs["value"] = b elif name == "w": rv_kwargs["value"] = w elif name == "w": rv_kwargs["value"] = w2 elif name == "z": rv_kwargs["value"] = z return rv_constructor(*rv_args, **rv_kwargs) return interceptor
核心问题分析
- 变量列表错误:
var_list传入的是Edward的随机变量(qb, qw等),但TensorFlow优化器需要优化的是TensorFlow可训练变量(即你定义的qb_mean, qb_stddv这类变量),随机变量本身不是可训练参数。 - TF版本模式冲突:代码混合了TensorFlow 1.x的
tf.Session()和TF2.x的tf.optimizers.Adam,minimize在即时执行模式下需要梯度带,而旧版会话模式不兼容。
修复步骤
1. 修正优化变量列表
把var_list替换为实际的可训练TF变量:
var_list = [qb_mean, qw_mean, qw2_mean, qz_mean, qb_stddv.variables[0], qw_stddv.variables[0], qw2_stddv.variables[0], qz_stddv.variables[0]]
注:qb_stddv是tf.nn.softplus包装的,需要取其内部的变量(variables[0])作为可训练参数。
2. 适配TF会话模式的优化流程
TF1.x风格的会话中,不能直接用TF2.x的optimizer.minimize,需要手动计算梯度并更新:
optimizer = tf.train.AdamOptimizer(learning_rate=0.05) grads = tf.gradients(-elbo, var_list) train_op = optimizer.apply_gradients(zip(grads, var_list))
之后在会话中运行train_op代替原来的train。
3. 完整训练循环修正
把原来的训练部分替换为:
optimizer = tf.train.AdamOptimizer(learning_rate=0.05) var_list = [qb_mean, qw_mean, qw2_mean, qz_mean, qb_stddv.variables[0], qw_stddv.variables[0], qw2_stddv.variables[0], qz_stddv.variables[0]] grads = tf.gradients(-elbo, var_list) train_op = optimizer.apply_gradients(zip(grads, var_list)) init = tf.global_variables_initializer() t = [] num_epochs = 500 with tf.Session() as sess: sess.run(init) for i in range(num_epochs): sess.run(train_op) if i % 5 == 0: current_elbo = sess.run(elbo) t.append(current_elbo) print(f"Epoch {i}, ELBO: {current_elbo}") # 最后一次性获取所有推断结果,避免循环内重复计算 b_mean_inferred, b_stddv_inferred, w_mean_inferred, w_stddv_inferred, \ w2_mean_inferred, w2_stddv_inferred, z_mean_inferred, z_stddv_inferred = sess.run([ qb_mean, qb_stddv, qw_mean, qw_stddv, qw2_mean, qw2_stddv, qz_mean, qz_stddv ])
4. 修复其他小问题
replace_latents函数里有重复的elif name == "w":,把第二个改成name == "w2":
elif name == "w2": rv_kwargs["value"] = w2
内容的提问来源于stack exchange,提问作者thomas41on1
相关产品推荐
相关产品推荐

