You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于TensorFlow的深度RL多动作模型训练梯度异常问题求助

问题分析
  1. 原损失函数逻辑错误:当前损失用-tf.reduce_mean(predicted_action * reward),但reward是前序动作的反馈,和当前预测动作无因果关系,梯度方向完全错误,无法引导网络优化到能获得高奖励的动作。
  2. 梯度为空的原因:如果直接用前序action计算损失,损失值和actor网络的predicted_action没有关联,TensorFlow的梯度带(GradientTape)无法追踪到actor变量的依赖关系,所以返回空梯度。
解决方案(基于REINFORCE策略梯度)

针对连续动作空间的RL任务,你需要用策略梯度算法(比如REINFORCE),核心是让网络学习“执行某个动作后获得高奖励,就提升这个动作被选中的概率”。具体修正步骤如下:

1. 调整Actor网络的输出(适配连续动作)

因为你的动作是二维连续向量,通常actor网络需要输出动作的均值(可选加上标准差,固定或可学习),用高斯分布来采样动作,这样才能计算动作的对数概率(用于策略梯度损失)。

示例Actor网络结构(假设你用LSTM):

class Actor(tf.keras.Model):
    def __init__(self):
        super().__init__()
        self.lstm1 = tf.keras.layers.LSTM(64, return_sequences=True)
        self.lstm2 = tf.keras.layers.LSTM(64)
        self.dense = tf.keras.layers.Dense(2)  # 输出二维动作均值

    def call(self, inputs):
        x = self.lstm1(inputs)
        x = self.lstm2(x)
        action_mean = tf.nn.sigmoid(self.dense(x))  # 假设动作范围是[0,1],用sigmoid约束
        return action_mean

2. 保存完整轨迹数据

训练前需要收集每个episode的轨迹:(state_t, action_t, reward_t),最后计算每个步骤的折扣累积奖励G_t(即从t到episode结束的所有奖励按折扣因子γ加权求和)。

添加缓冲区存储轨迹:

def __init__(self):
    # 其他初始化代码...
    self.state_buffer = []
    self.action_buffer = []
    self.reward_buffer = []
    self.gamma = 0.95  # 折扣因子,可调整

环境交互时存入数据:

# 示例交互逻辑
state = env.reset()
done = False
while not done:
    action_mean = self.actor(tf.convert_to_tensor([state], dtype=tf.float32))
    # 从高斯分布采样动作(添加小噪声保证探索)
    action = tf.random.normal(shape=action_mean.shape, mean=action_mean, stddev=0.1)
    action = tf.clip_by_value(action, 0.0, 1.0)  # 约束动作在合理范围
    next_state, reward, done, _ = env.step(action.numpy()[0])
    
    # 存入缓冲区
    self.state_buffer.append(state)
    self.action_buffer.append(action.numpy()[0])
    self.reward_buffer.append(reward)
    
    state = next_state

3. 计算折扣累积奖励

每个episode结束后,计算每个步骤的G_t:

def compute_discounted_rewards(self):
    discounted_rewards = []
    running_add = 0
    # 从后往前计算折扣奖励
    for r in reversed(self.reward_buffer):
        running_add = r + self.gamma * running_add
        discounted_rewards.insert(0, running_add)
    # 归一化奖励(稳定训练)
    discounted_rewards = tf.convert_to_tensor(discounted_rewards, dtype=tf.float32)
    discounted_rewards = (discounted_rewards - tf.reduce_mean(discounted_rewards)) / (tf.math.reduce_std(discounted_rewards) + 1e-8)
    return discounted_rewards

4. 修正训练函数

基于轨迹数据计算策略梯度损失:损失 = -E[ logπ(a|s) * G ],其中logπ(a|s)是动作a在状态s下的对数概率,G是折扣累积奖励。

def train_step(self):
    # 计算折扣累积奖励
    discounted_rewards = self.compute_discounted_rewards()
    
    states = tf.convert_to_tensor(self.state_buffer, dtype=tf.float32)
    actions = tf.convert_to_tensor(self.action_buffer, dtype=tf.float32)
    
    with tf.GradientTape() as tape:
        action_means = self.actor(states, training=True)
        # 计算动作的对数概率(假设动作服从高斯分布,标准差固定为0.1)
        log_probs = -0.5 * tf.reduce_sum(tf.square((actions - action_means)/0.1) + tf.math.log(2 * tf.constant(math.pi)) + tf.math.log(tf.square(0.1)), axis=1)
        # 策略梯度损失
        loss = -tf.reduce_mean(log_probs * discounted_rewards)
    
    # 计算梯度并更新网络
    grads = tape.gradient(loss, self.actor.trainable_variables)
    self.optimizer.apply_gradients(zip(grads, self.actor.trainable_variables))
    
    # 清空缓冲区
    self.state_buffer.clear()
    self.action_buffer.clear()
    self.reward_buffer.clear()
    
    # 更新探索噪声(可选,比如逐渐减小标准差)
    # self.epsilon = self.epsilon * self.epsilon_dec

5. 修复奖励函数的小问题

移除冗余代码并确保返回奖励值:

def transform_actions_to_reward(actions, state, agent, tipo, iteration):
    actions = actions[0]
    energy = state[0]
    price = state[1]
    battery_charge = state[2]

    percentage_stored = actions[0]
    percentage_empty = actions[1]

    energy_stored = energy * percentage_stored
    energy_iny = energy * (1 - percentage_stored)
    battery_iny = agent.battery * percentage_empty

    agent.fill_bat(energy_stored)

    if price == 1:
        reward = energy_iny + battery_iny
    elif price == 0:
        reward = -(energy_iny + battery_iny)
    
    return reward  # 必须返回奖励值
关键注意点
  • 连续动作空间下,不能直接用动作值乘奖励,必须用策略的对数概率来关联动作和奖励,这样梯度才能正确传递到actor网络的参数。
  • 折扣累积奖励的归一化能大幅提升训练稳定性,避免奖励波动导致梯度爆炸/消失。
  • 探索机制:连续动作通常用高斯噪声添加到均值上,而不是epsilon-greedy(后者更适合离散动作),可以随着训练逐渐减小噪声标准差来降低探索。

内容的提问来源于stack exchange,提问作者gustavo lobos astorquiza

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 06:05:03