TensorFlow中如何将计算损失应用到图中?报错无优化变量
嘿,我来帮你拆解下这个问题!你遇到的ValueError: No variables to optimize其实是几个小问题凑到一起导致的,咱们一步步理清楚:
核心问题分析
优化节点不在模型的图上下文里
你的类专门创建了self.graph来管理所有模型节点,但在discriminator()方法里创建optimize时,没有把这个操作放到self.graph.as_default()的上下文环境中!TensorFlow默认会把新节点加到全局默认图里,而你的模型权重变量都在self.graph里,优化器自然找不到要更新的变量。提前Run出模型输出,断开了梯度链
你先调用self.sess.run(self.dis_output)把专家/新手的输出转成了numpy数组,再用tf.reduce_mean计算损失——这时候的损失张量和模型的权重变量完全没有关联,优化器根本找不到需要优化的对象!必须在计算图里直接完成损失定义,保留损失和变量之间的梯度连接。变量名拼写错误
__init__里你定义的是self.learning_rate_dist,但后面优化器用的是self.learning_rate_dis,这会直接导致属性不存在的错误,得先统一变量名。
修正后的完整代码
import tensorflow as tf import numpy as np class Discriminator: # 类名首字母大写更符合Python规范 def __init__(self, n_actions, learning_rate): self.n_actions = n_actions self.learning_rate = learning_rate # 统一变量名,避免拼写错误 self.graph = tf.Graph() # 所有图节点的创建都放在self.graph的上下文里 with self.graph.as_default(): # 定义专家和新手动作的输入占位符 self.expert_input = tf.placeholder(tf.float32, [None, self.n_actions]) self.novice_input = tf.placeholder(tf.float32, [None, self.n_actions]) # 封装判别器网络,避免重复定义 def build_discriminator(inputs): x = tf.layers.dense(inputs, 16, tf.nn.relu) x = tf.layers.dense(x, 16, tf.nn.relu) return tf.layers.dense(x, 1) # 计算专家和新手的判别输出 expert_out = build_discriminator(self.expert_input) novice_out = build_discriminator(self.novice_input) # 用内置交叉熵函数计算损失,比手动log更稳定(避免log(0)的数值问题) expert_loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits( logits=expert_out, labels=tf.ones_like(expert_out) )) novice_loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits( logits=novice_out, labels=tf.zeros_like(novice_out) )) self.total_loss = expert_loss + novice_loss # 提前定义优化操作,和模型变量在同一个图里 self.optimizer = tf.train.AdamOptimizer(self.learning_rate).minimize(self.total_loss) # 初始化所有变量 init = tf.global_variables_initializer() self.sess = tf.Session(graph=self.graph) self.sess.run(init) def train_step(self, expert_actions, novice_actions): # 执行一次训练,返回当前损失值 _, current_loss = self.sess.run( [self.optimizer, self.total_loss], feed_dict={ self.expert_input: expert_actions.astype(np.float32), self.novice_input: novice_actions.astype(np.float32) } ) return current_loss if __name__ == '__main__': d = Discriminator(2, 0.001) # 注意输入要匹配placeholder的形状:[batch_size, n_actions],转成float32类型 expert_actions = np.random.randint(2, size=(10, 2)) novice_actions = np.random.randint(2, size=(10, 2)) loss = d.train_step(expert_actions, novice_actions) print(f"第一次训练损失:{loss}")
关键修改点说明
- 所有图相关操作(包括损失、优化器)都放到
self.graph.as_default()上下文里,确保模型变量和优化操作在同一个图中。 - 用TensorFlow内置的
sigmoid_cross_entropy_with_logits计算损失,避免手动tf.log可能出现的数值不稳定问题。 - 调整输入数据的形状,确保和占位符的
[None, n_actions]匹配(原来的一维数组会导致形状不匹配错误)。 - 把训练逻辑封装成
train_step方法,代码结构更清晰。
内容的提问来源于stack exchange,提问作者shunyo
相关产品推荐
相关产品推荐

