问题描述(Black Jack):

黑杰克(Blackjack)又名21点,起源于法国,有着悠久的历史。在世界各地的赌场中都很流行的一种游戏,使用除大小王之外的52张牌,游戏者的目标是使手中的牌的点数之和不超过21点且尽量大。扑克点数的计算规则:2至9牌,按其原点数计算;K、Q、J和10牌都算作10点(一般记作T,即ten之意);A牌(Ace)既可算作1点也可算作11点,由玩家自己决定。

游戏规则(不同玩法略有不同,下面是简单两人玩法,一庄一闲):

  1. 开局,庄闲各发两张牌,庄家一张明牌一张暗牌。如果庄闲其中一个牌面点数为21,则胜出。点数都为21,平局。否则继续。
  2. 拿牌流程:闲可以选择拿牌(hit)、停牌(stick)。若选择拿牌,在发牌的过程中,如果玩家的牌点数的和超过21,玩家就输了—叫爆掉(Bust),庄家赢。如玩家没爆掉,又决定不再要牌了(停牌),则轮到庄家。庄家翻开暗牌,并持续拿牌直至点数不小于17(若有Ace,按最大而尽量不爆计算)。如果庄家爆掉了,玩家赢;否则那么比点数大小,大为赢。点数相同为平局。

问题抽象

21点问题可以看作一个有限的马尔可夫决策过程:

  • sss : 状态(闲);Ace,玩家(闲)的牌面,庄家的明牌牌面。
  • aaa : 动作;要牌(hit:1),停牌(stick:0)。
  • rrr : 奖励;[-1,0, 1],输,赢,平。
  • γ=1\gamma = 1γ=1

问题求解

对于21点游戏,在没有完整的环境模型的情况下,不能使用DP方面来寻找最优策略。但是可以通过蒙特卡洛方法来求解最优策略,MC方法只需要从环境种收集足够的状态、动作、奖励序列数据就能对值函数进行估计。进而找到最优策略。

假设玩家的策略为πp\pi_pπp : 当牌面点数为20或21时,停牌,否则拿牌。采用MC方法计算策略πp\pi_pπp的值函数vπ(s)v_{\pi}(s)vπ(s), 庄家的固定策略πd\pi_dπd:当点数小于17时,一直拿牌,否则停牌。

模拟游戏过程

记录状态、动作、奖励。

import warnings
import numpy as np
import seaborn as sns
import matplotlib.pyplot as plt
from collections import namedtuple
from tqdm.notebook import tqdmwarnings.filterwarnings('ignore')
# player policy
def player_policy(usable_ace_player, cards_num, dealer_card1):# 1:拿牌,0: 停牌if cards_num < 20:return 1else:return 0
# dealer policy
def dealer_policy(cards_num):if cards_num < 17:return 1else:return 0
def play_blackjack(policy_player, policy_dealer, initial_state=None, initial_action=None):'''policy_player : function input state return actionpolicy_dealer : return -> reward, trajectory'''def card_value(card):return 11 if card == 1 else card# 闲player_sum = 0# 庄dealer_card1 = 0dealer_card2 = 0# trajectoryplayer_trajectory = []player_transition = namedtuple('Transition', ['state', 'action'])# False : Ace = 1, True Ace = 11usable_ace_player = Falseusable_ace_dealer = Falseif initial_state is None:while player_sum < 12:# 点数小于12,一直拿牌card = min(np.random.randint(1, 14), 10)#print(card)# 小于12,Ace = 11player_sum += card_value(card)# 点数超过21if player_sum > 21:# Ace = 1player_sum -= 10else:usable_ace_player |= (1 == card)# 初始化庄家牌,第一张为明牌dealer_card1 = min(np.random.randint(1, 14), 10)dealer_card2 = min(np.random.randint(1, 14), 10)else:# 指定初始状态usable_ace_player, player_sum, dealer_card1 = initial_statedealer_card2 = min(np.random.randint(1, 14), 10)dealer_sum = card_value(dealer_card1) + card_value(dealer_card2)usable_ace_dealer = 1 in (dealer_card1, dealer_card2)if dealer_sum > 21:# use Ace = 1dealer_sum -= 10# 闲先while True:if initial_action is not None:player_action = initial_actioninitial_action = Noneelse:player_action = policy_player(usable_ace_player, player_sum, dealer_card1)# 状态,动作player_sa = player_transition((usable_ace_player, player_sum, dealer_card1), player_action)player_trajectory.append(player_sa)if player_action == 0:break# 拿牌,默认Ace = 11card = min(np.random.randint(1, 14), 10)#print(card)# Keep track of the ace countace_count = int(usable_ace_player)if card == 1:ace_count += 1player_sum += card_value(card)# 避免bust ,Ace = 1while player_sum > 21 and ace_count:player_sum -= 10ace_count -= 1if player_sum > 21:return -1 , player_trajectoryusable_ace_player = (ace_count == 1)# 庄while True:dealer_action = policy_dealer(dealer_sum)if dealer_action == 0:break# 拿牌,默认Ace = 11new_card = min(np.random.randint(1, 14), 10)#print(card)ace_count = int(usable_ace_dealer)if new_card == 1:ace_count += 1dealer_sum += card_value(new_card)# 避免bust,Ace = 1while dealer_sum > 21 and ace_count:dealer_sum -= 10ace_count -= 1if dealer_sum > 21:return 1 , player_trajectoryusable_ace_dealer = (ace_count == 1)if player_sum > dealer_sum:return 1 , player_trajectoryelif player_sum == dealer_sum:return 0 , player_trajectoryelse:return -1 , player_trajectory
player_reward, player_traj = play_blackjack(player_policy, dealer_policy)
# 结果
player_reward
-1
player_traj
[Transition(state=(False, 12, 10), action=1),Transition(state=(False, 15, 10), action=1)]

状态值函数估计vπ(s)v_{\pi}(s)vπ(s)

  • First-visit MC : 只考虑每一局(episode)种状态sss第一次出现的情况。
  • Every-visit MC : 考虑每一局种sss多次重复出现的情况。
  • 两种方法的收敛效果是一致的。
First-visit MC
  • Input: a policy π\piπ to be evaluated
  • Initialize: V(s)∈RV(s) \in RV(s)R,arbitrarily,for all s∈Ss \in \mathcal SsS,Returns(s)←Returns(s) \getsReturns(s) an empty list, for all s∈Ss \in SsS
  • Loop forever (for each episode):
    • Generate an episode following π:S0,a0,R1,S1,a1,R2,...,ST−1,aT−1,RT\pi : S_0, a_0, R_1, S_1, a_1, R_2,...,S_{T-1},a_{T-1},R_Tπ:S0,a0,R1,S1,a1,R2,...,ST1,aT1,RT
    • G←0G \gets 0G0
    • Loop for each step of episode,t=T−1,T−2,...,0t = T-1, T-2, ...,0t=T1,T2,...,0:
      • G=γG+Rt+1G = \gamma G + R_{t+1}G=γG+Rt+1
      • Unless StS_tSt appears in S0,S1,...St−1S_0,S_1,...S_{t-1}S0,S1,...St1:
        • Append GGG to Returns(St)Returns(S_t)Returns(St)
        • V(St)←average(Retruns(St))V(S_t) \gets average(Retruns(S_t))V(St)average(Retruns(St))

γ=1\gamma = 1γ=1的情况下,每个episode中状态的值,跟游戏结束时的reward是一样的。

def monte_carlo_state_value_estimate(episodes, gamma=1.0):# player policystates_usable_ace = np.zeros((10, 10))states_usable_ace_count = np.ones((10, 10))states_no_usable_ace = np.zeros((10, 10))states_no_usable_ace_count = np.ones((10, 10))for i in tqdm(range(0, episodes)):player_reward, player_traj = play_blackjack(player_policy, dealer_policy)player_states = [t.state for t in player_traj]player_actions = [t.action for t in player_traj]player_rewards = [0]*len(player_states)player_rewards[-1] = player_rewardR = 0Gs = []for r in player_rewards[::-1]:R = r + gamma * RGs.insert(0, R)for player_state, G in zip(player_states, Gs):usable_ace_player, player_sum, dealer_card = player_stateplayer_sum -= 12dealer_card -= 1if usable_ace_player:states_usable_ace_count[player_sum, dealer_card] += 1states_usable_ace[player_sum, dealer_card] += Gelse:states_no_usable_ace_count[player_sum, dealer_card] += 1states_no_usable_ace[player_sum, dealer_card] += Greturn states_usable_ace / states_usable_ace_count, states_no_usable_ace / states_no_usable_ace_count
可视化值函数

Ace = 11 和 Ace = 1, 两种不同状态下值函数vπ(s)v_{\pi}(s)vπ(s)

在没有环境模型的情况下,只对状态的值进行估计是不够的,虽然知道了每个状态对应的期望回报,但是不知道如何过渡到这个状态(采取什么动作)。在之前MDP问题中,都有一个已知的环境模型(即:P(s′,r∣s,π(s))P(s',r|s,\pi(s))P(s,rs,π(s))),然后计算出每个动作和下一个状态对应的期望值,选择最佳的动作。因此,在环境模型未知的情况下,需要对动作值进行估计(或状态动作值,即:qπ(s,a)q_{\pi}(s,a)qπ(s,a)),动作值函数直接表示策略。基于蒙特卡洛方法的动作值函数估计跟状态值的估计是一样的,都是通过计算平均的回报。

动作值函数估计q(s,a)q(s,a)q(s,a)

状态值函数的估计只包含整个状态空间s∈Ss \in SsS,动作值函数的估计参数空间为S×A,a∈AS \times A, a \in AS×A,aA,如果状态和参数空间比较大,那么(s,a)(s,a)(s,a)的组合空间会更大,为了能够准确的估计动作值,需要尽可能的多遍历整个的s−as-asa空间,在游戏过程中。无尽的游戏次数肯定可以满足但是这个并不实际,所以需要采取一些策略,在游戏时间上做一些平衡。

  1. 随机开始,从随机状态开始游戏。
Monte Carlo ES(Exploring Starts)
  • Initialize:

    • π(s)∈A(s)\pi(s) \in \mathcal A(s)π(s)A(s)(arbitrartily),for all s∈S.s \in \mathcal S.sS.
    • Q(s,a)∈RQ(s,a) \in \mathcal RQ(s,a)R (arbitrartily),for all s∈S,a∈A(s)s \in \mathcal S, a \in \mathcal A(s)sS,aA(s).
    • Returns(s,a)←Returns(s,a) \getsReturns(s,a) empty list, for all$ s \in \mathcal S, a \in \mathcal A(s)$.
  • Loop forever (for each episode):
    • Choose S0∈S,A0∈A(S0)S_0 \in \mathcal S, A_0 \in \mathcal A(S_0)S0S,A0A(S0) randomly all pairs have probability > 0
    • Generate an episode from S0,A0S_0,A_0S0,A0 following π\piπ: S0,A0,R1,...,ST−1,AT−1,RTS_0, A_0, R_1,...,S_{T-1},A_{T-1},R_TS0,A0,R1,...,ST1,AT1,RT
    • G←0G \gets 0G0
    • Loop for each step of episode, t=T−1,T−2,...,0t = T-1, T-2, ..., 0t=T1,T2,...,0:
      • G←γG+Rt+1G \gets \gamma G + R_{t+1}GγG+Rt+1
      • Unless the pair St,AtS_t,A_tSt,At appears in S0,A0,S1,A1,...,St−1,At−1S_0,A_0,S_1,A_1,...,S_{t-1},A_{t-1}S0,A0,S1,A1,...,St1,At1:
        • Append GGG to Returns(St,At)Returns(S_t, A_t)Returns(St,At)
        • Q(St,At)←Q(S_t, A_t) \getsQ(St,At) average(Returns(St,At)Returns(S_t,A_t)Returns(St,At))
        • π(St)←argmaxaQ(St,a)\pi(S_t) \gets argmax_{a} Q(S_t, a)π(St)argmaxaQ(St,a)
update q(s,a)q(s,a)q(s,a),采用用下面的方式

q(s,a)←q(s,a)×(s,a)count+q(s,a)new((s,a)count+1)q(s,a) \gets \frac{q(s,a) \times (s,a)_{count} + q(s,a)_{new}}{\big((s,a)_{count} + 1\big)}q(s,a)((s,a)count+1)q(s,a)×(s,a)count+q(s,a)new

def monte_carlo_es(episodes, gamma=1.0):sa_history = []# Initializestate_action_values = np.zeros((10, 10, 2, 2))state_action_pair_count = np.ones((10, 10, 2, 2))# argmax_a(sa)def greedy_policy(usable_ace, player_sum, dealer_card):usable_ace = int(usable_ace)player_sum -= 12dealer_card -= 1values_ = state_action_values[player_sum, dealer_card, usable_ace, :]#return np.argmax(values_)# e: values_=[0, 0], random choicereturn np.random.choice([action_ for action_, value_ in enumerate(values_) if value_ == np.max(values_)])# Loop for each episodefor episode in tqdm(range(episodes)):# Randomly Initializeinitial_state = [bool(np.random.randint(0, 2)),np.random.randint(12, 22),np.random.randint(1, 11)]initial_action = np.random.randint(0, 2)# Generate an episode#current_policy = greedy_policy if episode else player_policyplayer_reward, player_traj = play_blackjack(greedy_policy, dealer_policy, initial_state, initial_action)player_states = [t.state for t in player_traj]player_actions = [t.action for t in player_traj]player_rewards = [0]*len(player_states)player_rewards[-1] = player_rewardR = 0Gs = []for r in player_rewards[::-1]:R = r + gamma * RGs.insert(0, R)for player_state,action, G in zip(player_states, player_actions, Gs):usable_ace_player, player_sum, dealer_card = player_stateusable_ace = int(usable_ace_player)player_sum -= 12dealer_card -= 1# Update values of state-actionold_val = state_action_values[player_sum, dealer_card, usable_ace, action]sa_count = state_action_pair_count[player_sum,dealer_card, usable_ace, action]new_val = (old_val * sa_count + G)/(sa_count + 1)state_action_values[player_sum, dealer_card, usable_ace, action] = new_valstate_action_pair_count[player_sum, dealer_card, usable_ace, action] += 1sa_history.append(state_action_values.copy())return state_action_values, sa_history
可视化动作值

由于维度限制,所以用不用的颜色来表示动作值的差异。

  • usable_Ace
  • no usable_Ace
  • 颜色越深,值越大


Usable Ace

  1. usable Ace

  1. Nousable Ace

最后:

q(s,a)q(s,a)q(s,a)矩阵就是策略的具体内容,最优策略π∗(s)=argmaxa(q(s,a))\pi^{*}(s) = {argmax}_a(q(s,a))π(s)=argmaxa(q(s,a)).

动作值函数的收敛过程动画

马尔科夫决策过程(MDP) : BlackJack问题(MC-ES)相关推荐

  1. 强化学习note1——马尔科夫奖励过程MRP和马尔科夫决策过程MDP各个函数的定义与区别

    马尔科夫奖励过程MRP 状态转移函数:P(St+1=s′∣st=s)P\left(S_{t+1}=s^{\prime} \mid s_{t}=s\right)P(St+1​=s′∣st​=s) 奖励函 ...

  2. 强化学习(二)马尔科夫决策过程(MDP)

    在强化学习(一)模型基础中,我们讲到了强化学习模型的8个基本要素.但是仅凭这些要素还是无法使用强化学习来帮助我们解决问题的, 在讲到模型训练前,模型的简化也很重要,这一篇主要就是讲如何利用马尔科夫决策 ...

  3. 强化学习——马尔科夫决策过程 MDP

    马尔可夫决策过程是强化学习里面的一个基本框架. 马尔可夫过程.马尔可夫反馈过程是马尔可夫决策过程的基础,所以本博客将会一并介绍. 文章目录 1. 马尔科夫过程 Markov Process,MP 1. ...

  4. 强化学习——day13 马尔科夫决策过程MDP

    马尔科夫决策过程 简介 马尔可夫过程 随机过程 马尔可夫性质 马尔可夫过程 马尔可夫奖励过程 回报 价值函数 马尔可夫决策过程 策略 状态价值函数 动作价值函数 贝尔曼期望方程 蒙特卡洛方法 占用度量 ...

  5. 强化学习 马尔科夫决策过程(MDP)

    1. 强化学习引入MDP的原因 强化学习的环境的状态转化模型,它可以表示为一个概率模型,即在状态下采取动作a,转到下一个状态s′的概率,表示为 如果按照真实的环境转化过程看,转化到下一个状态s′的概率 ...

  6. 马尔科夫决策过程(MDP)

    聊一聊我对强化学习的理解 对应的代码请访问我的GitHub:fxyang-bupt(可能你进去之后发现什么都没有,那是因为我注册了新的账号还在整理,这并不影响你先follow一下我的GitHub~) ...

  7. 强化学习——day11 马尔科夫决策过程MDP

    第 3 章 马尔可夫决策过程 3.1 简介 马尔可夫决策过程(Markov decision process,MDP)是强化学习的重要概念.要学好强化学习,我们首先要掌握马尔可夫决策过程的基础知识.前 ...

  8. 【强化学习入门】马尔科夫决策过程

    本文介绍了马尔可夫决策过程,首先给出了马尔可夫决策过程的定义形式 ,其核心是在时序上的各种状态下如何选择最优决策得到最大回报的决策序列,通过贝尔曼方程得到累积回报函数:然后介绍两种基本的求解最优决策的 ...

  9. 强化学习课程笔记(二)——马尔科夫决策过程和动态规划寻找最优策略

    参考材料 1.强化学习入门课程(英文)https://www.bilibili.com/video/av37295048 2.课程对应知乎讲解https://zhuanlan.zhihu.com/re ...

  10. 马尔科夫决策过程(MDP)五大元素

    文章目录 什么是马尔科夫决策过程(Markove Decision Progress, MDP)? MDP五大元素 什么是决策规则(Decision Rules,DR) 什么是策略 什么是马尔科夫决策 ...

最新文章

  1. 辍学的名人_我辍学去追求成为网络开发人员和设计师的梦想
  2. 【转】在Java中连接字符串时是使用+号还是使用StringBuilder StringBuffer 加号
  3. [ASP.NET] Session 详解
  4. 笔记-项目立项管理-项目建议书
  5. string中删除一个元素
  6. 多线程同步中sleep与wait区别
  7. CRM product UI里assignment block的显示隐藏逻辑
  8. [css] 写一个动画,向上匀速移动100px,向下以1.5倍速度移动200px,一直反复循环
  9. 【2016.11.17】HTML学习笔记第二天
  10. jdk、cglib动态代理代码示例
  11. vs设计窗口不见了_龙猫腕表评测:VS沛纳海320V2版本
  12. SQL语言之关系运算与多表操作(五)
  13. SQL Server 数据类型
  14. java applet实例_java applet 一个简单的例子(applet+html)
  15. Java聊天室系统的设计与实现(完整源码 sql文件 论文)
  16. 标书制作,全流程视频教程大全
  17. 金山词霸2009牛津with SP3完全破解版(含全部本地词库和语音包)
  18. openfoam一些报错的原因(持续更新)
  19. flutter学习笔记--传递信息
  20. sklearn中predict()与predict_proba()返回值意义

热门文章

  1. linux使用中的问题 --- (防火墙iptables -F)
  2. linux shell let命令,linux shell let, expr 命令详解
  3. 上面两点下面一个三角形_【人人都能欣赏的数学证明】为什么三角形的三个内角相加是180度?...
  4. python模拟足球比赛_博客园仿真足球竞赛平台Python版SDK
  5. android 的接口回调,android 接口 接口回调
  6. 增加小球python,python实现弹跳小球
  7. RHEL6.3基本网络配置(4) 其它常用网络配置文件
  8. JBOSS7 学习 一 只能127.0.0.1 访问控制台
  9. 用X264编码以后的H264数据
  10. centos防火墙设置