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

CarRacing环境下DQN智能体训练遇阻:学习进度停滞

自研CarRacing环境中DQN智能体无法有效学习

我正尝试在自研CarRacing环境中训练DQN智能体,但始终无法让智能体产生有效学习——回合总奖励始终处于低位且无提升。

环境构建代码

def make_env():
    env = RacingEnvironment(render_mode = "rgb_array")
    env = NormalizeReward(env, gamma = 0.99, epsilon = 1e-8)
    env = DilatedFrameStack(env, num_stack = 4, dilation = 12)
    return env

奖励曲线

奖励曲线

模型结构

class DQN(nn.Module):
    def __init__(self, action_size):
        super(DQN, self).__init__()

        self.features = nn.Sequential(
            nn.Conv2d(4, 16, kernel_size=3, stride=3),  # (16, 41, 41)
            nn.BatchNorm2d(16),
            nn.LeakyReLU(0.2, inplace=True),

            nn.Conv2d(16, 32, kernel_size=3, stride=2),  # (32, 20, 20)
            nn.BatchNorm2d(32),
            nn.LeakyReLU(0.2, inplace=True),
            nn.Dropout2d(0.1),

            nn.Conv2d(32, 64, kernel_size=3, stride=2),  # (64, 9, 9)
            nn.BatchNorm2d(64),
            nn.LeakyReLU(0.2, inplace=True),
            nn.Dropout2d(0.1),

            nn.Conv2d(64, 96, kernel_size=3, stride=2),  # (96, 4, 4)
            nn.BatchNorm2d(96),
            nn.LeakyReLU(0.2, inplace=True)
        )

        self.flatten = nn.Flatten()

        self.mlp = nn.Sequential(
            nn.Linear(96 * 4 * 4, 256),
            nn.ReLU(),
            nn.Dropout(0.2),
            nn.Linear(256, action_size)
        )

    def forward(self, x):
        x = self.features(x)
        x = self.flatten(x)
        return self.mlp(x)

补充背景信息

  • 输入为4张带时间间隔的灰度帧堆叠(尺寸(4, 84, 84))。
    输入帧示例
  • 动作空间已离散化:0-前进,1-右转,2-左转
  • 采用标准DQN训练框架:经验回放池(ReplayBuffer)、目标网络、ε-贪婪探索等

奖励函数

def _calculate_reward(self, collision: bool) -> float:
    progress_reward = self.car.checkpoint_index * 0.5
    collision_penalty = -30.0 if collision else 0.0

    _, distances = self.car.get_rays_and_distances(self.TRACK_BORDER_MASK)
    wall_penalty = -5.0 if distances[6] or distances[0] or distances[4] <= 25 else 1.0
    speed_bonus = -3.0 if distances[6] <= 60 and self.car.vel >= 4 else 2.0
    return progress_reward + collision_penalty + wall_penalty + speed_bonus

训练循环

EPOCHS = 500_000
BATCH_SIZE = 32
agent.decay_steps = 350_000

state = env.reset()
progress_bar = trange(0, EPOCHS)
for i in progress_bar:

    agent.update_epsilon_value(i)
    _, state = play_and_record(state, agent, env, n_steps = 1)
    loss, grad_norm = agent.replay(BATCH_SIZE)

    if i % 50 == 0:
        td_loss_history.append(loss)
        grad_norm_history.append(grad_norm)

    if i % 10_000 == 0:
       agent.synchronize()

    if i % 1000 == 0:
       torch.save(agent.Q_model.state_dict(), save_path)
       mean_rw_history.append(evaluate(make_env(), agent, n_games = 2, greedy = True, t_max = 500))

       clear_output(True)
       print("Buffer size = %i, epsilon = %.5f" % (len(agent.memory), agent.epsilon))
       plt.figure(figsize = [15, 4])
       plt.subplot(1, 3, 1)
       plt.title("Mean reward per game")
       plt.plot(mean_rw_history, color = 'dodgerblue')
       plt.grid(color = 'black', ls = '--', alpha = 0.5)

       assert not np.isnan(td_loss_history[-1])
       plt.subplot(1, 3, 2)
       plt.title("TD loss history")
       plt.plot(smoothen(td_loss_history), color = 'crimson')
       plt.grid(color = 'black', ls = '--', alpha = 0.5)

       plt.subplot(1, 3, 3)
       plt.title("Grad norm history")
       plt.plot(smoothen(grad_norm_history), color = 'lime')
       plt.grid(color = 'black', ls = '--', alpha = 0.5)
       plt.tight_layout()
       plt.show()

辅助函数

def play_and_record(initial_state, agent, env, n_steps = 1):
    """执行恰好n步游戏,将每个(s, a, r, s', done)记录到回放池。返回累计奖励和环境当前状态。"""
    s = initial_state
    sum_rewards = 0.0

    for _ in range(n_steps):

        a = agent.get_action(s)
        next_s, r, terminated, truncated, _ = env.step(a)

        done = (terminated or truncated)

        agent.remember(s, a, r, next_s, done)
        sum_rewards += r

        s = env.reset() if done else next_s

    return sum_rewards, s

def evaluate(env, agent, n_games = 1, greedy = False, t_max = 10_000):
    """运行n_games局完整游戏。如果greedy为True,则选择qvalues最大的动作。返回平均奖励。"""

    rewards = []
    for _ in range(n_games):

        s = env.reset()
        s = s / 255.0
        reward = 0

        for _ in range(t_max):

            action = agent.get_best_action(s) if greedy else agent.get_action(s)
            s, r, done, truncated, _ = env.step(action)
            s = s / 255.0
            reward += r

            if done or truncated:
               break

        rewards.append(reward)
    return np.mean(rewards)

经验回放池状态

回放池数据示例正常:
回放池数据示例1
回放池数据示例2

疑问

问题可能出在哪里?我的模型架构针对该任务是否存在问题?或是使用DQN训练CarRacing存在需要注意的已知挑战?恳请提供建议或经验分享!


内容的提问来源于stack exchange,提问作者papierowka

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.12 22:44:54