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

蒙特卡洛方法求解21点:Q值表异常问题排查

蒙特卡洛算法求解21点问题:Q值表异常排查

我正遵循Sutton和Barto的方法,实现蒙特卡洛(Monte Carlo)算法求解21点(Blackjack)问题。代码逻辑看似无误,但生成的Q值表显示在过多场景下建议选择stick(停牌)操作,无法确定是方法思路存在偏差还是代码实现有误。

智能体类代码(Epsilon-Greedy策略)

class MonteCarloAgentEpsilonGreedy:
    def __init__(
        self,
        env,
        discount_factor,
        epsilon):

        self.env = env
        self.gamma = discount_factor
        self.epsilon = epsilon  # 探索率
        # 创建存储Q值的字典
        self.Q_values = defaultdict(lambda: np.zeros(env.action_space.n))
        self.Returns = defaultdict(lambda: np.zeros(env.action_space.n))
        self.N = defaultdict(lambda: np.zeros(env.action_space.n))

    def get_action(self, obs):
        """
        根据给定观测值选择动作(Epsilon-Greedy策略)

        参数:
            obs: 用于确定动作的观测值

        返回:
            action: 以1-epsilon概率选择Q值最高的动作,否则随机选择动作
        """

        if np.random.rand() < self.epsilon:
            action = self.env.action_space.sample() # 随机选择动作
        else:
            action = int(np.argmax(self.Q_values[obs])) # 选择Q值最高的动作

        return action

    def update_Q_values(self, episode):
        """
        根据回合数据更新Q值

        参数:
            episode: 包含(state, action, reward)元组的列表
        """
        G = 0
        for state, action, reward in reversed(episode):
            G = self.gamma * G + reward
            self.Returns[state][action] += G
            self.N[state][action] += 1
            # Q值更新规则
            self.Q_values[state][action] = self.Returns[state][action] / self.N[state][action]

主函数代码

if __name__ == "__main__":
    env = gym.make('Blackjack-v1', natural=False, sab=False)

    # 创建MonteCarloAgent实例
    agent = MonteCarloAgentEpsilonGreedy(
        env, discount_factor=0.9, epsilon=0.1)

    num_episodes = 1000000

    for e in range(num_episodes):

        episode = []
        terminated = False
        truncated = False
        # 随机初始化状态
        observation, info = env.reset()

        while (not terminated and not truncated):  # 回合循环

            action = agent.get_action(observation)

            next_obs, reward, terminated, truncated, info = env.step(action)
            episode.append((observation, action, reward))
        agent.update_Q_values(episode)
    

    env.close()

部分观测对应的Q值示例

  • (15, 10, 0): array([-0.57322077, -0.57813051])
  • (19, 3, 0): array([ 0.39937642, -0.67754011])
  • (17, 10, 0): array([-0.45902484, -0.68447894])
  • (11, 8, 0): array([-0.47658631, -0.47728385])
  • (12, 10, 0): array([-0.54324405, -0.5438698 ])
  • (20, 10, 0): array([ 0.44418773, -0.84017038])
  • (11, 10, 0): array([-0.54170763, -0.54247852])
  • (15, 3, 0): array([-0.24095023, -0.49996364])
  • (18, 6, 0): array([ 0.28397257, -0.6047619 ])
  • (20, 4, 0): array([ 0.65904186, -0.87462687])
  • (13, 8, 0): array([-0.50007986, -0.50656757])
  • (13, 6, 0): array([-0.14338235, -0.38048843])
  • (17, 5, 0): array([-0.03217932, -0.57848101])

Q值表可视化结果

Q值表可视化结果
注:蓝色代表stick(停牌)场景,红色代表hit(要牌)场景

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 00:38:23