zoukankan      html  css  js  c++  java
  • 利用蒙特卡洛方法实现21点问题的最优解(内含python源码)

    想要获取完整代码,请访问面包多进行支持哦,仅需一口奶茶的钱!

    一、实验目的

    实现基于蒙特卡洛法的21点问题的最优解,了解强化学习的基本原理,理解蒙特卡洛法并编写相应的代码。

    二、实验内容

    赌场上流行的21点纸牌游戏的目的是获得其数值之和尽可能大而不超过21的牌。所有的人形牌面都算作10,而A可以算作1或11。我们的实验仅考虑每个玩家独立与庄家竞争的版本。游戏开始时,庄家和玩家都有两张牌。庄家的一张牌面朝上,另一张牌面朝下。如果玩家有21张牌(一张A和一张10牌),则称为自然牌。他就赢了,除非庄家也有自然牌,在这种情况下,游戏是平局。如果玩家没有自然牌,那么他可以要求额外的牌,单张发牌(hits),直到他停止(sticks)或超过21(goes bust)。如果他破产,那么他输了,如果他坚持,那么就轮到庄家的回合。庄家hits或sticks或者goes bust;在牌数字和为17或更多的时候,庄家就停止发牌。赢、输、或平局由谁的最终和值更接近21决定。

    三、实验过程

    本次实验需要导入如下包:

    import gym
    import numpy as np
    from collections import defaultdict
    import matplotlib
    import matplotlib.pyplot as plt
    

    运用gym自带的21点游戏进行接下来的编程:

    env = gym.make('Blackjack-v0')
    observation = env.reset()
    print(env.action_space, env.observation_space, sep='
    ')
    

    这段代码返回了玩家的当前点数之和 ∈{0,1,…,31} ,庄家朝上的牌点数之和 ∈{1,…,10} ,及玩家是否有能使用的ace(no =0 、yes =1 ),和智能体可以执行两个潜在动作:STICK = 0,HIT = 1。

    本次实验采用On-policy first-visit MC control,On-policy方法在一定程度上解决了exploring starts这个假设,让策略既greedy又exploratory,最后得到的策略也一定程度上达到最优。如下图所示:

    图 1 On-policy first-visit MC control

    图 2 树

    我们定义一个嵌套函数:

    def make_epsilon_greedy_policy(Q_table, nA, epsilon):
        def generate_policy(observation):
            prob_A = np.ones(nA) * epsilon / nA
            optimal_a = np.argmax(Q_table[observation])
            prob_A[optimal_a] += (1.0 - epsilon)
            return prob_A
    
        return generate_policy
    

    MC算法是逐幕进行的,所以我们要根据策略来生成一幕数据。

    这里要注意:generate_policy是一个函数即make_epsilon_greedy_policy的返回值。generate_policy的返回值是 π piπ 。这里循环了1000次只是为了确保能获得完整的一幕。

    接下来是MC控制的主体部分,我们要循环足够多的次数使得价值函数收敛,每次循环都首先根据策略生成一幕样本序列,然后遍历每个“状态—价值”二元组,并用所有首次访问的回报的平均值作为估计.

    这里要注意:Return和Count是字典,每个“状态—价值”二元组是一个key,该二元组每一幕的回报是它的value,随着越来越多的迭代,根据大数定律,它的平均值会收敛到它的期望值。并且在下一轮迭代生成另外一幕样本序列的时候,generate_policy函数会根据Q_table更新。

    def MC_control(env, iteration_times=500000, epsilon=0.1, discount_factor=1.0):
        Return, Count, Q_table = defaultdict(float), defaultdict(float), defaultdict(lambda: np.zeros(env.action_space.n))
        policy = make_epsilon_greedy_policy(Q_table, env.action_space.n, epsilon)
        for i in range(iteration_times):
            if i % 1000 == 0:
                print(str(i) + "次")
    
            trajectory = generate_one_episode(env, policy)
            s_a_pairs = set([(x[0], x[1]) for x in trajectory])
            for state, action in s_a_pairs:
                s_a = (state, action)
                first_visit_id = next(i for i, x in enumerate(trajectory) if x[0] == state and x[1] == action)
                G = sum([x[2] * (discount_factor ** i) for i, x in enumerate(trajectory[first_visit_id:])])
                Return[s_a] += G
                Count[s_a] += 1.
                Q_table[state][action] = Return[s_a] / Count[s_a]
        return policy, Q_table
    

    接下来是将价值函数可视化:

    def plot_value_function(Q_table):
        x = np.arange(12, 21)
        y = np.arange(1, 10)
        X, Y = np.meshgrid(x, y)
        Z_noace = np.apply_along_axis(lambda x: Q_table[(x[0], x[1], False)], 2, np.dstack([X, Y]))
        Z_ace = np.apply_along_axis(lambda x: Q_table[(x[0], x[1], True)], 2, np.dstack([X, Y]))
            def plot_surface(X, Y, Z, title):
            	代码过长略
    

    实验结束。想要获取完整代码,请访问面包多进行购买

    四、实验结果

    运行如上代码,在代码文件RL中,输出图所示:

    图 3 not use Ace

    图 4 use ace


  • 相关阅读:
    [HAOI2015]按位或
    【bzoj 4675】 点对游戏
    [WC2013]糖果公园
    [国家集训队]数颜色 / 维护队列
    【bzoj 3252】攻略
    [ZJOI2016]小星星
    hdu-1712 ACboy needs your help---分组背包
    hdu-2844&&POJ-1742 Coins---多重背包
    UVA-147 Dollars---完全背包+打表
    hdu-2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活---多重背包
  • 原文地址:https://www.cnblogs.com/sabai/p/14158680.html
Copyright © 2011-2022 走看看