想要獲取完整代碼,請訪問麪包多進行支持哦,僅需一口奶茶的錢!python
實現基於蒙特卡洛法的21點問題的最優解,瞭解強化學習的基本原理,理解蒙特卡洛法並編寫相應的代碼。算法
賭場上流行的21點紙牌遊戲的目的是得到其數值之和儘量大而不超過21的牌。全部的人形牌面都算做10,而A能夠算做1或11。咱們的實驗僅考慮每一個玩家獨立與莊家競爭的版本。遊戲開始時,莊家和玩家都有兩張牌。莊家的一張牌面朝上,另外一張牌面朝下。若是玩家有21張牌(一張A和一張10牌),則稱爲天然牌。他就贏了,除非莊家也有天然牌,在這種狀況下,遊戲是平局。若是玩家沒有天然牌,那麼他能夠要求額外的牌,單張發牌(hits),直到他中止(sticks)或超過21(goes bust)。若是他破產,那麼他輸了,若是他堅持,那麼就輪到莊家的回合。莊家hits或sticks或者goes bust;在牌數字和爲17或更多的時候,莊家就中止發牌。贏、輸、或平局由誰的最終和值更接近21決定。編程
本次實驗須要導入以下包:app
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='\n')
這段代碼返回了玩家的當前點數之和 ∈{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,最後獲得的策略也必定程度上達到最優。以下圖所示:spa
咱們定義一個嵌套函數:3d
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算法是逐幕進行的,因此咱們要根據策略來生成一幕數據。code
這裏要注意:generate_policy是一個函數即make_epsilon_greedy_policy的返回值。generate_policy的返回值是 π \piπ 。這裏循環了1000次只是爲了確保能得到完整的一幕。blog
接下來是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中,輸出圖所示: