部分專有名詞在上一篇文章有介紹,本文不作過多贅述。

目錄

  • 前言
  • 演算法思想
  • 演算法詳解
  • 演算法公式
  • 探險者尋寶藏實戰(一維)

前言

我們做事情都會有自己的一個行為準則,比如小時候爸媽常說「不寫完作業就不準看電視」。所以我們在寫作業的狀態(state)下,好的行為就是繼續寫作業,直到寫完它,我們還可以得到獎勵(reward),不好的行為就是沒寫完作業就跑去看電視了,被爸媽發現就會被懲罰,這種事情做的多了,也變成了我們不可磨滅的記憶,這其實就是一個Q-learning的決策過程。

演算法思想

Q-Learning是強化學習演算法中value-based的演算法,Q即為Q(s,a),就是在某一個時刻的state狀態下,採取動作a能夠獲得收益的期望,環境會根據agent的動作反饋相應的reward獎賞,所以演算法的主要思想就是將stateaction構建成一張Q_table表來存儲Q值,然後根據Q值來選取能夠獲得最大收益的動作。

Q-learning的主要優勢就是使用了時間差分法(融合了蒙特卡洛和動態規劃)能夠進行off-policy的學習,使用貝爾曼方程可以對馬爾科夫過程求解最優策略,本文對其中演算法不進行推導,會另外寫一篇推導的文章。

演算法詳解

我們還是用一開始舉的做作業的例子來說明:

假設我們的行為準側已經學習好了,現在我們處於狀態s1,我在寫作業,我有兩個行為a1,a2,分別是看電視和寫作業,根據我的經驗(Q-table)知道,在s1的狀態下,我選擇a2寫作業帶來的reward獎賞比a1看電視高,在我的Q-table中,Q(s1,a1)=-2要小於Q(s1,a2)=1,所以我們判斷要選擇a2寫作業作為我們的下一個行為。現在我們的狀態更新成s2,我們還是有兩個同樣的選擇,重複上面的過程,在行為準則Q-table中尋找Q(s2,a1)Q(s2,s2)的值,並比較他們的大小,選取較大的一個。接著根據a2我們到達s3並重複上述的決策過程,Q-learning的方法就是這樣抉擇的。那我們的Q-table這張行為決策表又是如何決策的呢?我們來看看。

回到之前的流程,根據Q表的估計,因為在s1中,a2的值比較大,通過之前的決策方法我們在s1選擇了a2,併到達s2,這時我們開始更新用於決策的Q表,接著我們並沒有在實際中採取任何行為,而是在想像自己在s2上採取了a1,a2兩個行為,分別看看兩種行為哪一個的Q值大,比如說Q(s2,a2)的值比Q(s2,a1)的大,所以我們把大的Q(s2,a2)乘上一個衰減值gamma(eg 0.9)並加上到達s2時所獲得的獎勵Reward(這裡沒有獲取到我們的棒棒糖,所以獎勵為0),因為會獲取實實在在的獎勵Reward,所以我們將這個作為我們現實中Q(s1,a2)的值,但是我們之前是根據Q表估計Q(s1,a2)的值。所以有了現實值和估計值,我們就可以更新Q(s1,a2)的值,變成新的值。但時刻記住,我們雖然用maxQ(s2)估算了一下s2的狀態,但還沒有在S2做出任何行為,s2的行為決策要等到更新完了以後再重新另外做,這就是off-policyQ-learning是如何決策和學習優化決策過程。

演算法公式

這一張圖概括了我們之前所有的內容。這也就是Q-learning演算法,每次更新我們都用到了Q現實Q估計,而且Q-learning迷人之處就是在Q(s1,a2)的現實中,包含了一個**Q(s2)**的最大估計值,將對下一步衰減的最大估計和當前所得到的獎勵作為這一步的現實。

參數介紹

  • Epsilon greedy:是用在決策上的一個策略,比如epsilon = 0.9的時候,就說明百分之90的情況我會按照Q表的最優值選擇行為,百分之10的時間隨機選擇行為。
  • alpha:學習率,決定這次的誤差有多少是要被學習的。
  • gamma:對未來reward的衰減值。gamma越接近1,機器對未來的reward越敏感

探險者尋寶藏實戰(一維)

背景

在一個一維時間,在世界的右邊有寶藏,探險者只要得到寶藏嘗到了甜頭,以後就會記住得到寶藏的方法,這就是他用強化學習所學習到的行為。

在這個遊戲中,o所在的每個地點就是每個狀態,而每個地點探險者所可以做出left/right兩個行為,這就是探險者可以做出的action,而每種行為在每個狀態下都會有一個值,也就是Q(s,a),如果在某個地點s1,探險者計算了Q(s1,a1)和Q(s1,a2),如果前者大於後者,那麼探險者就會選擇left這個行為,這就是行為準則

預設參數

import numpy as np
import pandas as pd
import time

np.random.seed(2) # reproducible

N_STATES = 6 #一維世界的寬度
ACTIONS = [left,right] #探索者可用的動作
EPSILON = 0.9 #greedy貪婪度
ALPHA = 0.1 #學習率
GAMMA = 0.9 #獎勵遞減值
MAX_EPISODES = 13 #最大回合數
FRESH_TIME = 0.3 #每回合移動間隔時間

Q表

我們要將所有Q values放在q_table中,更新q_table也是在更新他的行為準則。q_tableindex是所有對應的state(o所在的位置)columns是對應的action(探險者選擇left或者right)

def build_q_table(n_states, actions):
table = pd.DataFrame(
np.zeros((n_states, len(actions))), # q_table 全 0 初始
columns=actions, # columns 對應的是行為名稱
)
return table

# q_table:
"""
left right
0 0.0 0.0
1 0.0 0.0
2 0.0 0.0
3 0.0 0.0
4 0.0 0.0
5 0.0 0.0
"""

定義action

接著定義探險者是如何挑選行為的,這就是我們引入epsilon greedy的概念。因為在初始階段,隨機的探索環境,往往比固定的行為模式要好,所以這也是累積經驗的階段,我們希望探險者不那麼貪婪(greedy),所以EPSILON就是用來控制貪婪程度的值。EPSILON可以隨著探險時間不斷提升(越來越貪婪),不過在這個例子中,我們就固定EPSILON=0.9,90%的時間是選擇最優策略,10%的時間來探索。

def choose_action(state, q_table):
state_actions = q_table.iloc[state, :] # 選出這個state的所有 action的value值
if (np.random.uniform() > EPSILON) or (state_actions.all() == 0): #非貪婪 or 或者這個 state 還沒有探索過
action_name = np.random.choice(ACTIONS)
else:
action_name = state_actions.idxmax() # 貪婪模式
return action_name

環境的反饋S_,R

做出行為後,環境也要給我們的行為一個反饋,反饋出下一個state(S_)和上一個state(S)做出action(A)所得到的reward(R)。這裡定義的規則是,只有當o移動到了T(探險者獲取了寶藏),探險者才會得到唯一的獎勵,獎勵值R=1,其他情況沒有獎勵。

def get_env_feedback(S,A):
if A== right: #往右探險
if S == N_STATES - 2: #找到寶藏
S_ = terminal
R = 1
else:
S_ = S + 1
R = 0
else: #往左探險
R = 0
if S == 0:
S_ = S #碰壁
else:
S_ = S - 1
return S_,R

環境更新

接下來就是環境的更新了,這裡不多贅述。

def update_env(S, episode, step_counter):
env_list = [-]*(N_STATES-1) + [T] # ---------T our environment
if S == terminal:
interaction = Episode %s: total_steps = %s % (episode+1, step_counter)
print(
{}.format(interaction), end=)
time.sleep(2)
print(
, end=)
else:
env_list[S] = o
interaction = .join(env_list)
print(
{}.format(interaction), end=)
time.sleep(FRESH_TIME)

強化學習的主循環

最重要的地方就是這裡,將剛才理論部分我們講解到的演算法實現出來。

def rl():
q_table = bulid_q_table(N_STATES,ACTIONS) #初始化q_table
for episode in range(MAX_EPISODES): #回合
step_counter = 0
S = 0 #回合初始的位置
is_terminated = False
update_env(S,episode,step_counter) #環境更新
while not is_terminated:

A = choose_action(S,q_table) #選擇行為
S_,R = get_env_feedback(S,A) #實施行為並得到環境的反饋
q_predict = q_table.loc[S,A] #估算的(狀態-行為)值
if S_ != terminal:
q_target = R + GAMMA*q_table.iloc[S_,:].max() #實際的(狀態-行為)值
else:
q_target = R #實際的(狀態-行為值)
is_terminated = True

q_table.loc[S,A] += ALPHA*(q_target - q_predict) #q_table更新
S = S_ #更新探索者位置

update_env(S,episode,step_counter+1)

step_counter += 1
return q_table

結果

我們可以看到,一開始沒有任何經驗的探險者需要非常多次的嘗試才能找到寶藏,而隨著探險次數的增多,最後就可以自己走到寶藏的地方了。

第一次尋寶藏需要38步
到第12次尋寶藏只需要5步
我們可以看到 right的value值最後是比left高的

參考:

github.com/MorvanZhou

各位看官看完有用或者感興趣的話點個贊把~別光收藏

推薦閱讀:

相關文章